Wiem, że łańcuch automatycznego układu składa się zasadniczo z 3 różnych procesów.
- aktualizacja ograniczeń
- widoki układu (tutaj otrzymujemy obliczenia ramek)
- pokaz
To, co nie jest do końca jasne, to wewnętrzna różnica między -setNeedsLayout
i -setNeedsUpdateConstraints
. Z Apple Docs:
Wywołaj tę metodę w głównym wątku aplikacji, jeśli chcesz dostosować układ widoków podrzędnych widoku. Ta metoda odnotowuje żądanie i natychmiast zwraca. Ponieważ ta metoda nie wymusza natychmiastowej aktualizacji, ale zamiast tego czeka na następny cykl aktualizacji, można jej użyć do unieważnienia układu wielu widoków przed aktualizacją któregokolwiek z tych widoków. To zachowanie pozwala skonsolidować wszystkie aktualizacje układu w jednym cyklu aktualizacji, co zwykle jest lepsze ze względu na wydajność.
Gdy właściwość widoku niestandardowego zmienia się w sposób, który wpływałby na ograniczenia, można wywołać tę metodę, aby wskazać, że ograniczenia muszą zostać zaktualizowane w pewnym momencie w przyszłości. System wywoła następnie updateConstraints jako część normalnego przejścia do układu. Aktualizowanie wiązań naraz tuż przed ich użyciem zapewnia, że nie trzeba niepotrzebnie ponownie obliczać wiązań, gdy między zmianami układu wprowadzanych jest wiele zmian w widoku.
Kiedy chcę animować widok po zmodyfikowaniu ograniczenia i animować zmiany, które zwykle wywołuję na przykład:
[UIView animateWithDuration:1.0f delay:0.0f usingSpringWithDamping:0.5f initialSpringVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
[self.modifConstrView setNeedsUpdateConstraints];
[self.modifConstrView layoutIfNeeded];
} completion:NULL];
Odkryłem, że jeśli mogę użyć -setNeedsLayout
zamiast -setNeedsUpdateConstraints
wszystko działa zgodnie z oczekiwaniami, ale jeśli zmieni -layoutIfNeeded
się -updateConstraintsIfNeeded
, animacja nie stanie.
Próbowałem wyciągnąć własny wniosek:
-updateConstraintsIfNeeded
aktualizuje tylko ograniczenia, ale nie wymusza przejścia układu na proces, dlatego oryginalne ramki są nadal zachowywane-setNeedsLayout
wywołuje także-updateContraints
metodę
Więc kiedy można używać jednego zamiast drugiego? a jeśli chodzi o metody układu, czy muszę je wywoływać w widoku, który ma zmianę ograniczenia, czy w widoku nadrzędnym?
Odpowiedzi:
Twoje wnioski są słuszne. Podstawowy schemat to:
setNeedsUpdateConstraints
zapewnia przyszłe połączenie zupdateConstraintsIfNeeded
połączeniamiupdateConstraints
.setNeedsLayout
zapewnia przyszłe połączenie zlayoutIfNeeded
połączeniamilayoutSubviews
.Kiedy
layoutSubviews
jest wywoływany, również dzwoniupdateConstraintsIfNeeded
, więc moim zdaniem rzadko jest potrzebne ręczne wywoływanie go. W rzeczywistości nigdy go nie nazwałem, z wyjątkiem debugowania układów.Aktualizowanie za pomocą ograniczeń
setNeedsUpdateConstraints
jest również dość rzadkie, objc.io - należy przeczytać o autoukładach - mówi :Ponadto, z mojego doświadczenia, nigdy nie musiałem unieważniać ograniczeń i nie ustawiać
setNeedsLayout
następnego wiersza kodu, ponieważ nowe ograniczenia w zasadzie wymagają nowego układu.Podstawowe zasady to:
setNeedsLayout
.updateConstraints
metoda (zalecanym sposobem ograniczenia zmian, btw), zadzwońsetNeedsUpdateConstraints
, a większość czasu,setNeedsLayout
po tym.layoutIfNeeded
.Ponadto w twoim kodzie animacji uważam, że nie
setNeedsUpdateConstraints
jest to konieczne, ponieważ ograniczenia są aktualizowane ręcznie przed animacją, a animacja rozkłada widok tylko na podstawie różnic między starymi i nowymi.źródło
setNeedsLayout
.setNeedsLayout
żelayoutSubviews
zostanie wywołana w następnym cyklu aktualizacji, ale może to nie ma nic wspólnegolayoutIfNeeded
?layoutSubviews
zostanie wywołany automatycznie, nie musisz dzwonićsetNeedsLayout
layoutSubviews
, więc nie trzeba tego robić ręcznie. Musisz jednak zadzwonić,layoutIfNeeded
jeśli chcesz, aby zmiany odniosły skutek natychmiast zamiast następnego cyklu układuOdpowiedź przez coverback jest całkiem poprawne. Chciałbym jednak dodać kilka dodatkowych szczegółów.
Poniżej znajduje się schemat typowego cyklu UIView, który wyjaśnia inne zachowania:
-setNeedsLayout
zamiast-setNeedsUpdateConstraints
wszystko działa zgodnie z oczekiwaniami, ale jeśli zmieni-layoutIfNeeded
się-updateConstraintsIfNeeded
, animacja nie stanie.updateConstraints
zazwyczaj nic nie robi. Po prostu rozwiązuje ograniczenia, ale nie stosuje ich, dopóki nielayoutSubviews
zostanie wywołane. Tak więc animacja wymaga połączenia zlayoutSubviews
.Nie, to nie jest konieczne. Jeśli twoje ograniczenia nie zostały zmodyfikowane, UIView pominie połączenie z
updateConstraints
. Musisz jawnie zadzwonić,setNeedsUpdateConstraint
aby zmodyfikować ograniczenia w tym procesie.Aby zadzwonić
updateConstraints
, wykonaj następujące czynności:źródło