Uwaga : od czasu zadania tego pytania sytuacja się zmieniła; zobacz tutaj, aby uzyskać dobry przegląd.
Przed automatycznym układem można było zmienić punkt zakotwiczenia warstwy widoku bez przesuwania widoku, przechowując ramkę, ustawiając punkt zakotwiczenia i przywracając ramkę.
W świecie automatycznego układu nie ustawiamy już ramek, ale wydaje się, że ograniczenia nie wystarczają do dostosowania pozycji widoku z powrotem do miejsca, w którym chcemy. Możesz zhakować ograniczenia, aby zmienić położenie widoku, ale przy obracaniu lub innych zdarzeniach zmiany rozmiaru stają się one ponownie nieważne.
Następujący genialny pomysł nie działa, ponieważ tworzy „nieprawidłowe połączenie atrybutów układu (lewy i szerokość)”:
layerView.layer.anchorPoint = CGPointMake(1.0, 0.5);
// Some other size-related constraints here which all work fine...
[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:layerView
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:layerView
attribute:NSLayoutAttributeWidth
multiplier:0.5
constant:20.0]];
Moim zamiarem było ustawienie lewej krawędzi layerView
widoku z dostosowanym punktem zakotwiczenia na połowę jego szerokości plus 20 (odległość, którą chcę wstawić od lewej krawędzi nadzoru).
Czy można zmienić punkt zakotwiczenia bez zmiany położenia widoku w widoku z układem automatycznym? Czy muszę używać wartości zakodowanych na stałe i edytować ograniczenie przy każdym obrocie? Mam nadzieję, że nie.
Muszę zmienić punkt zakotwiczenia, aby po zastosowaniu transformacji do widoku uzyskać prawidłowy efekt wizualny.
źródło
layerView
znasz jego szerokość? Czy przykleja swoją prawą stronę do czegoś innego?//Size-related constraints that work fine
- szerokość i wysokość widoku warstwy pochodzi z superwiewu.Odpowiedzi:
[EDYCJA: Ostrzeżenie: cała następująca dyskusja zostanie prawdopodobnie przestarzała lub przynajmniej mocno złagodzona przez iOS 8, który może już nie popełniać błędu uruchamiania układu w momencie zastosowania transformacji widoku].
Autoukład a widok przekształceń
Autolayout nie działa dobrze z transformacjami widoku. Powód, o ile mogę stwierdzić, jest taki, że nie należy mieszać w ramkę widoku, który ma transformację (inną niż domyślna transformacja tożsamości) - ale właśnie to robi autoukład. Sposób działania autoukładu polega na tym, że w
layoutSubviews
środowisku wykonawczym przechodzi przez wszystkie ograniczenia i odpowiednio ustawia klatki wszystkich widoków.Innymi słowy, ograniczenia nie są magiczne; to tylko lista rzeczy do zrobienia.
layoutSubviews
to miejsce, w którym lista rzeczy do zrobienia jest wykonywana. I robi to poprzez ustawienie ramek.Nie mogę pomóc w traktowaniu tego jako błędu. Jeśli zastosuję tę transformację do widoku:
Spodziewam się, że widok pojawi się ze środkiem w tym samym miejscu co poprzednio i będzie o połowę mniejszy. Ale w zależności od ograniczeń może to wcale nie być to, co widzę.
[Właściwie jest tu druga niespodzianka: zastosowanie transformacji do widoku natychmiast uruchamia układ. Wydaje mi się, że to kolejny błąd. A może jest to sedno pierwszego błędu. To, czego bym się spodziewał, to móc uciec z transformacją przynajmniej do czasu rozmieszczenia, np. Urządzenie jest obrócone - tak jak mogę uciec z animacją klatki do czasu rozmieszczenia. Ale w rzeczywistości czas na przygotowanie jest natychmiastowy, co wydaje się po prostu niewłaściwe.]
Rozwiązanie 1: Brak ograniczeń
Jedno z obecnych rozwiązań polega na tym, że jeśli mam zamiar zastosować półtrwałą transformację do widoku (a nie tylko tymczasowo nim poruszać), usunąć wszystkie ograniczenia, które na niego wpływają. Niestety, zazwyczaj powoduje to zniknięcie widoku z ekranu, ponieważ nadal ma miejsce autoukład, a teraz nie ma żadnych ograniczeń, aby powiedzieć nam, gdzie umieścić widok. Więc oprócz usunięcia ograniczeń, ustawiłem widok na
translatesAutoresizingMaskIntoConstraints
TAK. Widok działa teraz w stary sposób, bez wpływu autoukładu. (Oczywiście ma na to wpływ autoukład, ale niejawne ograniczenia dotyczące autorezyzacji maski powodują, że jej zachowanie jest takie samo, jak przed autoukładem).Rozwiązanie 2: Używaj tylko odpowiednich ograniczeń
Jeśli wydaje się to nieco drastyczne, innym rozwiązaniem jest ustawienie ograniczeń, aby działały poprawnie z zamierzoną transformacją. Jeśli rozmiar widoku jest określany wyłącznie na podstawie swojej wewnętrznej stałej szerokości i wysokości i jest umieszczony wyłącznie według jego środka, na przykład moja transformacja skali będzie działać zgodnie z oczekiwaniami. W tym kodzie usuwam istniejące ograniczenia z widoku podrzędnego (
otherView
) i zastępuję je tymi czterema ograniczeniami, nadając mu stałą szerokość i wysokość oraz przypinając go wyłącznie po środku. Po tym moja transformacja skali działa:Wynik jest taki, że jeśli nie masz żadnych ograniczeń, które wpływają na ramkę widoku, autoukład nie dotknie ramki widoku - co jest właśnie tym, czego szukasz, gdy zaangażowana jest transformacja.
Rozwiązanie 3: Użyj widoku podrzędnego
Problem z obydwoma powyższymi rozwiązaniami polega na tym, że tracimy korzyści wynikające z ograniczeń pozycjonowania naszego punktu widzenia. Oto rozwiązanie, które to rozwiązuje. Zacznij od niewidocznego widoku, którego zadaniem jest wyłącznie pełnienie roli gospodarza, i użyj ograniczeń, aby go ustawić. Wewnątrz umieść prawdziwy widok jako podgląd podrzędny. Użyj ograniczeń, aby umieścić podgląd podrzędny w widoku nadrzędnym, ale ogranicz te ograniczenia do ograniczeń, które nie będą walczyć, gdy zastosujemy transformację.
Oto ilustracja:
Widok biały to widok hosta; powinieneś udawać, że jest przezroczysty i przez to niewidoczny. Widok czerwony to jego widok podrzędny, umieszczony przez przypięcie jego środka do środka widoku nadrzędnego. Teraz możemy bez problemu skalować i obracać czerwony widok wokół jego środka, a ilustracja rzeczywiście pokazuje, że to zrobiliśmy:
W międzyczasie ograniczenia widoku hosta utrzymują go we właściwym miejscu, gdy obracamy urządzenie.
Rozwiązanie 4: Zamiast tego użyj przekształceń warstw
Zamiast przekształceń widoku należy używać przekształceń warstw, które nie powodują wyzwalania układu, a tym samym nie powodują natychmiastowego konfliktu z ograniczeniami.
Na przykład ta prosta animacja widoku „pulsującego” może się zepsuć podczas automatycznego układania:
Mimo że ostatecznie nie nastąpiła zmiana rozmiaru widoku, wystarczy ustawić jego
transform
układ przyczyn, a ograniczenia mogą sprawić, że widok przeskoczy. (Czy to wygląda na błąd, czy co?) Ale jeśli zrobimy to samo z Core Animation (używając CABasicAnimation i stosując animację do warstwy widoku), układ nie występuje i działa dobrze:źródło
Miałem podobny Isuue i właśnie usłyszałem Back od zespołu Autolayout w Apple. Sugerują użycie podejścia Container View Approach, które sugeruje mat, ale tworzą podklasę UIView, aby nadpisać układ Podglądy i zastosować tam niestandardowy układ Kod - Działa jak urok
Plik nagłówkowy wygląda tak, że możesz połączyć wybrany widok podrzędny bezpośrednio z programu Interface Builder
a plik m stosuje specjalny kod w ten sposób:
Jak widać, przy pierwszym wywołaniu chwyta środkowy punkt widoku i ponownie wykorzystuje tę pozycję w kolejnych wywołaniach, aby odpowiednio umieścić widok. To nadpisuje kod autoukładu w tym sensie, że ma to miejsce po [super layoutSubviews]; który zawiera kod autoukładu.
W ten sposób nie ma już potrzeby unikania automatycznego układu, ale możesz utworzyć własny układ, gdy domyślne zachowania nie są już odpowiednie. Oczywiście możesz zastosować znacznie bardziej skomplikowane rzeczy niż to, co jest w tym przykładzie, ale to było wszystko, czego potrzebowałem, ponieważ moja aplikacja może używać tylko trybu portretu.
źródło
layoutSubviews
. Chciałbym tylko dodać, że tutaj Apple po prostu zmusza cię do robienia tego, co myślę, że powinni byli zrobić (w ich implementacji Autolayout) przez cały czas.Znajduję prosty sposób. Działa na iOS 8 i iOS 9.
Podobnie jak w przypadku dopasowania anchorPoint do układu opartego na ramkach:
Kiedy dostosowujesz zakotwiczenie widoku za pomocą automatycznego układu, robisz to samo, ale w sposób ograniczony. Gdy punkt anchorPoint zmieni się z (0,5, 0,5) na (1, 0,5), layerView przesunie się w lewo o połowę długości szerokości widoku, więc musisz to skompensować.
Nie rozumiem ograniczenia w pytaniu, więc załóżmy, że dodajesz ograniczenie centerX względem superView centerX ze stałą: layerView.centerX = superView.centerX + stała
źródło
Jeśli używasz automatycznego układu, nie widzę, jak ręczne ustawienie pozycji będzie służyć w dłuższej perspektywie, ponieważ w końcu automatyczny układ przeskoczy wartość pozycji ustawioną przez Ciebie podczas obliczania własnego układu.
Potrzebne jest raczej zmodyfikowanie samych ograniczeń układu, aby skompensować zmiany wywołane przez ustawienie anchorPoint. Następująca funkcja robi to dla nieprzekształconych widoków.
Przyznaję, że to prawdopodobnie nie wszystko, na co liczyłeś, ponieważ zwykle jedynym powodem, dla którego chcesz zmodyfikować anchorPoint, jest ustawienie transformacji. Wymagałoby to bardziej złożonej funkcji, która aktualizuje ograniczenia układu, aby odzwierciedlić wszystkie zmiany ramki, które mogą być spowodowane przez samą właściwość transform. Jest to trudne, ponieważ transformacje mogą wiele zmienić w ramce. Skalowanie lub transformacja obrotu spowodowałaby zwiększenie rozmiaru ramki, więc musielibyśmy zaktualizować wszelkie ograniczenia szerokości lub wysokości itp.
Jeśli używasz transformacji tylko do tymczasowej animacji, to, co powyżej, może wystarczyć, ponieważ nie wierzę, że automatyczny układ uniemożliwi animacji w locie przedstawianie obrazów, które reprezentują czysto przejściowe naruszenia ograniczeń.
źródło
tl: dr: Możesz utworzyć wylot dla jednego z ograniczeń, aby można go było usunąć i ponownie dodać.
Utworzyłem nowy projekt i dodałem widok o stałym rozmiarze w środku. Wiązania pokazano na poniższym obrazku.
Następnie dodałem wylot dla widoku, który ma się obracać, oraz dla wiązania wyrównania środek x.
Później
viewDidAppear
obliczam nowy punkt kontrolnyNastępnie usuwam ograniczenie, dla którego mam gniazdko, tworzę nowy, który jest przesunięty i dodaję go ponownie. Następnie mówię widokowi ze zmienionym ograniczeniem, że musi zaktualizować ograniczenia.
Na koniec dodaję animację obrotu do widoku obrotowego.
Wygląda na to, że obracająca się warstwa pozostaje wyśrodkowana (a powinna) nawet podczas obracania urządzenia lub w inny sposób powodująca aktualizację wiązań. Nowe wiązanie i zmieniony punkt kontrolny wizualnie znoszą się wzajemnie.
źródło
Moje obecne rozwiązanie polega na ręcznym dostosowaniu położenia warstwy w
viewDidLayoutSubviews
. Ten kod może być również użyty wlayoutSubviews
podklasie widoku, ale w moim przypadku mój widok jest widokiem najwyższego poziomu wewnątrz kontrolera widoku, więc oznaczało to, że nie musiałem tworzyć podklasy UIView.Wydaje się, że to zbyt duży wysiłek, więc inne odpowiedzi są mile widziane.
źródło
Zainspirowany odpowiedzią mojego Matta, postanowiłem spróbować innego podejścia. Można użyć widoku kontenera z odpowiednio zastosowanymi ograniczeniami. Widok ze zmodyfikowanym punktem zakotwiczenia można następnie umieścić w widoku kontenera, używając masek autoregulacji i wyraźnego ustawienia ramki, tak jak za dawnych złych czasów.
W każdym razie działa to wspaniale, jak na moją sytuację. Widoki są konfigurowane tutaj w viewDidLoad:
Nie ma znaczenia, że ramki widoku czerwonego są w tym momencie zerowe, ze względu na maskę autoreferencji w widoku zielonym.
Dodałem transformację rotacyjną do metody akcji i był to wynik:
Wydawało się, że gubi się podczas obracania urządzenia, więc dodałem do metody viewDidLayoutSubviews:
źródło
view.layer
spokoju i wykonać całą pracę w podwarstwie o formacieview.layer
. Innymi słowy, widok byłby po prostu obiektem nadrzędnym, a wszystkie transformacje rysunkowe i podwarstwy itd. Byłyby o poziom niższy, bez ograniczeń.Myślę, że tą metodą pokonujesz cel autoukładu. Wspomniałeś, że szerokość i prawa krawędź zależą od superwizji, więc dlaczego nie dodać po prostu ograniczeń wzdłuż tej linii myślenia?
Porzuć paradygmat anchorPoint / transform i spróbuj:
Te
NSLayoutAttributeRight
środki ograniczające dokładnie jakanchorPoint = CGPointMake(1.0, 0.5)
, aNSLayoutAttributeWidth
ograniczeniem jest grubsza odpowiada poprzednia kodeksuNSLayoutAttributeLeft
.źródło
anchorPoint
, chodzi mi o to, że nie powinieneś używać go do pomiarów. System autoukładu UIView powinien być niezależny od przekształceń CALayer. Więc UIView: układ, CALayer: wygląd / animacjeviewDidLayoutSubviews
powinna to naprawić;position
zawsze się zgadzaanchorPoint
. Moja odpowiedź pokazuje jedynie, jak zdefiniować ograniczenie dla transformacji tożsamości.To pytanie i odpowiedzi zainspirowały mnie do rozwiązania własnych problemów z Autolayout i skalowaniem, ale z scrollviews. Przykład mojego rozwiązania stworzyłem na githubie:
https://github.com/hansdesmedt/AutoLayout-scrollview-scale
To jest przykład UIScrollView z niestandardowym stronicowaniem całkowicie wykonanym w AutoLayout i jest skalowalny (CATransform3DMakeScale) z długim naciśnięciem i dotknięciem, aby powiększyć. Kompatybilny z iOS 6 i 7.
źródło
To duży temat i nie przeczytałem wszystkich komentarzy, ale miałem ten sam problem.
Miałem widok z XIB z autoukładem. Chciałem zaktualizować jego właściwość transform. Osadzenie widoku w widoku kontenera nie rozwiązuje mojego problemu, ponieważ autoukład działał dziwnie w widoku kontenera. Dlatego właśnie dodałem drugi widok kontenera, aby zawierał widok kontenera, który zawiera mój widok i zastosowałem w nim transformacje.
źródło
tl; dr Powiedzmy, że zmieniłeś punkt kontrolny na (0, 0). Punkt kontrolny znajduje się teraz w lewym górnym rogu. Zawsze można zobaczyć wyraz centrum w układzie automatycznym, należy pomyśleć górnym rogu .
Dostosowując anchorPoint, po prostu zmieniasz semantykę AutoLayout. Układ automatyczny nie będzie kolidował z punktem kotwiczenia ani odwrotnie. Jeśli tego nie rozumiesz, będziesz się źle bawić .
Przykład:
Rysunek A. Brak modyfikacji punktów kontrolnych
Rysunek B. Punkt zakotwiczenia zmieniono na lewy górny
Rysunek A i rysunek B wyglądają dokładnie tak samo. Nic się nie zmieniło. Zmieniła się tylko definicja tego, do którego centrum się odnosi.
źródło