setNeedsLayout vs. setNeedsUpdateConstraints i layoutIfNeeded vs updateConstraintsIfNeeded

Wiem, że łańcuch układu auto składa się w zasadzie z 3 różnych procesów.

  1. Aktualizacja ograniczeń
  2. widoki układu (tutaj otrzymujemy obliczenia ramek)
  3. wyświetlacz

To, co nie jest dla mnie do końca jasne, to wewnętrzna różnica między -setNeedsLayout i -setNeedsUpdateConstraints. Z Apple Docs:

SetNeedsLayout

Wywołaj tę metodę w głównym wątku aplikacji, Jeśli chcesz Dostosuj układ podglądów podglądu. Metoda ta zwraca uwagę na wniosek i zwraca natychmiast. Ponieważ metoda ta nie Wymuś natychmiastową aktualizację, ale zamiast tego czeka na następną aktualizację cyklu, można go użyć do unieważnienia układu wielu widoków zanim któryś z tych widoków zostanie zaktualizowany. To zachowanie pozwala na skonsoliduj wszystkie aktualizacje układu w jednym cyklu aktualizacji, który jest zwykle lepiej dla wydajności.

SetNeedsUpdateConstraints

Gdy właściwość widoku niestandardowego zmieni się w sposób, który wpłynie ograniczenia, można wywołać tę metodę, aby wskazać, że ograniczenia muszą być aktualizowane w pewnym momencie w przyszłości. System będzie wtedy wywołanie updateConstraints jako część jego normalnego przebiegu układu. Aktualizacja ograniczenia wszystkie naraz tuż przed ich potrzebą zapewnia, że nie niepotrzebnie przeliczać ograniczeń, gdy wiele zmian to wykonane do widoku pomiędzy przejściami układu.

Gdy chcę animować Widok po modyfikacji 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];

Dowiedziałem się, że jeśli użyję -setNeedsLayout zamiast -setNeedsUpdateConstraints Wszystko działa zgodnie z oczekiwaniami, ale jeśli zmienię -layoutIfNeeded na -updateConstraintsIfNeeded, animacja nie nastąpi.
Próbowałem wyciągnąć własne wnioski:

  • -updateConstraintsIfNeeded tylko zaktualizuj ograniczenia, ale nie wymusza wchodzenia w układ proces, dzięki czemu Oryginalne ramki są nadal zachowane
  • -setNeedsLayout wywołuje również metodę -updateContraints

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?

Author: Honey, 2013-12-16

2 answers

Twoje wnioski są słuszne. podstawowy schemat to:

  • setNeedsUpdateConstraints zapewnia przyszłe połączenie do updateConstraintsIfNeeded połączeń updateConstraints.
  • setNeedsLayout zapewnia przyszłe połączenie do layoutIfNeeded połączeń layoutSubviews.

Kiedy layoutSubviews jest wywołana, również wywołuje updateConstraintsIfNeeded, więc ręczne wywołanie jest rzadko potrzebne w moim doświadczeniu. W rzeczywistości nigdy go nie wywołałem, z wyjątkiem debugowania układów.

Aktualizowanie ograniczeń za pomocą setNeedsUpdateConstraints jest również dość rzadkie, objc. io-a MUSI przeczytać o autolayouts-says :

Jeśli później coś się zmieni, co unieważnia jedno z ograniczeń, należy natychmiast usunąć ograniczenie i wywołać setNeedsUpdateConstraints. w rzeczywistości jest to jedyny przypadek, w którym należy uruchomić przepustkę aktualizacji ograniczenia.

Ponadto, z mojego doświadczenia, nigdy nie musiałem unieważniać ograniczeń i nie ustawiać setNeedsLayout w następnej linii kodu, ponieważ nowe ograniczenia w zasadzie proszą o nowy layout.

Zasady są następujące:

  • jeśli manipulowałeś ograniczeniami bezpośrednio, zadzwoń setNeedsLayout.
  • jeśli zmienisz pewne warunki (takie jak offsety lub smth), które zmienią ograniczenia w Twojej nadpisanej metodzie updateConstraints (zalecany sposób zmiany ograniczeń, btw), wywołaj setNeedsUpdateConstraints, a przez większość czasu setNeedsLayout później.
  • jeśli potrzebujesz którejś z powyższych czynności, aby uzyskać natychmiastowy efekt-np. gdy musisz nauczyć się nowej wysokości klatki po layout pass-dodaj go za pomocą layoutIfNeeded.

Również, w Twoim kodzie animacji, uważam, że {[0] } jest niepotrzebny, ponieważ ograniczenia są aktualizowane przed animacją ręcznie, a animacja tylko odtwarza widok na podstawie różnic między starymi i nowymi.

 242
Author: coverback,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-27 15:44:40

Odpowiedź coverbacka jest całkiem poprawna . Chciałbym jednak dodać kilka dodatkowych szczegółów.

Poniżej znajduje się schemat typowego cyklu UIView, który wyjaśnia inne zachowania Cykl życia UIView

  1. dowiedziałem się, że jeśli użyję-setNeedsLayout zamiast-setNeedsUpdateConstraints wszystko działa zgodnie z oczekiwaniami, ale jeśli zmienię-layoutIfNeeded z-updateConstraintsIfNeeded, animacja nie nastąpi.

updateConstraints zazwyczaj nie robi cokolwiek. Po prostu rozwiązuje ograniczenia, nie stosuje ich do momentu wywołania layoutSubviews. Tak więc animacja wymaga wywołania layoutSubviews.

  1. również wywołania setNeedsLayout-metoda updateContraints
Nie, to nie jest konieczne. Jeśli Twoje ograniczenia nie zostały zmodyfikowane, UIView pominie wywołanie updateConstraints. Musisz jawnie wywołać setNeedsUpdateConstraint, aby zmodyfikować ograniczenia w procesie.

Aby zadzwonić updateConstraints należy wykonać następujące czynności:

   [view setNeedsUpdateConstraints];
   [view setNeedsLayout];
   [view layoutIfNeeded];
 72
Author: Kunal Balani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-22 17:12:15