Aktualizuję starą aplikację, AdBannerView
a gdy nie ma reklamy, zsuwa się z ekranu. Gdy pojawia się reklama, przesuwa się po ekranie. Podstawowe rzeczy.
W starym stylu ustawiłem ramkę w bloku animacji. W nowym stylu mam ograniczenie IBOutlet
do automatycznego układu, które określa Y
pozycję, w tym przypadku jest to odległość od dolnej części superview i modyfikuję stałą:
- (void)moveBannerOffScreen {
[UIView animateWithDuration:5 animations:^{
_addBannerDistanceFromBottomConstraint.constant = -32;
}];
bannerIsVisible = FALSE;
}
- (void)moveBannerOnScreen {
[UIView animateWithDuration:5 animations:^{
_addBannerDistanceFromBottomConstraint.constant = 0;
}];
bannerIsVisible = TRUE;
}
Baner przesuwa się dokładnie zgodnie z oczekiwaniami, ale nie ma animacji.
AKTUALIZACJA: Ponownie obejrzałem wykład WWDC 12 Najlepsze praktyki w zakresie masteringu auto-układu, który obejmuje animację. Omówiono, jak zaktualizować ograniczenia za pomocą CoreAnimation :
Próbowałem z następującym kodem, ale uzyskałem dokładnie takie same wyniki:
- (void)moveBannerOffScreen {
_addBannerDistanceFromBottomConstraint.constant = -32;
[UIView animateWithDuration:2 animations:^{
[self.view setNeedsLayout];
}];
bannerIsVisible = FALSE;
}
- (void)moveBannerOnScreen {
_addBannerDistanceFromBottomConstraint.constant = 0;
[UIView animateWithDuration:2 animations:^{
[self.view setNeedsLayout];
}];
bannerIsVisible = TRUE;
}
Na marginesie, sprawdzałem wiele razy i jest to wykonywane w głównym wątku.
Odpowiedzi:
Dwie ważne uwagi:
Musisz zadzwonić
layoutIfNeeded
w obrębie bloku animacji. Apple zaleca, aby wywołać go raz przed blokiem animacji, aby upewnić się, że wszystkie oczekujące operacje układu zostały zakończoneMusisz wywołać go konkretnie w widoku nadrzędnym (np.
self.view
), A nie w widoku podrzędnym, który ma związane z nim ograniczenia. Spowoduje to zaktualizowanie wszystkich ograniczonych widoków, w tym animację innych widoków, które mogą być ograniczone do widoku, dla którego zmieniono ograniczenie (np. Widok B jest przymocowany do dolnej części widoku A, a właśnie zmieniłeś górne przesunięcie widoku A i chcesz widok B animować go)Spróbuj tego:
Cel C
Szybki 3
źródło
setNeedsLayout
zamiastlayoutIfNeeded
. Jestem trochę przerażony, ile godzin spędziłem, nie zauważając, że właśnie wpisałem niewłaściwą nazwę metody.Doceniam udzieloną odpowiedź, ale myślę, że byłoby miło posunąć się nieco dalej.
Podstawowa animacja bloku z dokumentacji
ale tak naprawdę jest to bardzo uproszczony scenariusz. Co zrobić, jeśli chcę animować ograniczenia widoków cząstkowych za pomocą tej
updateConstraints
metody?Blok animacji, który wywołuje metodę podrzędności updateConstraints
Metoda updateConstraints jest zastępowana w podklasie UIView i musi wywoływać super na końcu metody.
Przewodnik AutoLayout pozostawia wiele do życzenia, ale warto je przeczytać. Sam używam tego jako elementu
UISwitch
przełączającego widok podrzędny za pomocą paryUITextField
s z prostą i subtelną animacją zwinięcia (o długości 0,2 sekundy). Ograniczenia dla widoku podrzędnego są obsługiwane w metodach updateConstraints podklasy UIView, jak opisano powyżej.źródło
self.view
(a nie w widoku podrzędnym tego widoku) wywołanieupdateConstraintsIfNeeded
nie jest konieczne (ponieważsetNeedsLayout
również wyzwalaczeupdateConstraints
tego widoku). Może to być najbardziej trywialne, ale do tej pory nie było dla mnie;)Zasadniczo wystarczy zaktualizować ograniczenia i wywołać
layoutIfNeeded
wewnątrz bloku animacji. Może to być zmiana.constant
właściwościNSLayoutConstraint
, dodanie ograniczeń usuwania (iOS 7) lub zmiana.active
właściwości ograniczeń (iOS 8 i 9).Przykładowy kod:
Przykładowa konfiguracja:
Spór
Istnieją pytania dotyczące tego, czy ograniczenie należy zmienić przed blokiem animacji, czy w środku nim (patrz poprzednie odpowiedzi).
Poniżej znajduje się rozmowa na Twitterze między Martinem Pilkingtonem, który uczy iOS, a Kenem Ferrym, który napisał Auto Layout. Ken wyjaśnia, że chociaż zmienianie stałych poza blokiem animacji może obecnie działać, nie jest to bezpieczne i naprawdę powinny być zmieniane w bloku animacji. https://twitter.com/kongtomorrow/status/440627401018466305
Animacja:
Przykładowy projekt
Oto prosty projekt pokazujący, jak można animować widok. Wykorzystuje Cel C i animuje widok, zmieniając
.active
właściwość kilku ograniczeń. https://github.com/shepting/SampleAutoLayoutAnimationźródło
źródło
Rozwiązanie Swift 4
UIView.animate
Trzy proste kroki:
Zmień ograniczenia, np .:
Poinformuj zawierający,
view
że jego układ jest brudny i że autoukład powinien ponownie obliczyć układ:W bloku animacji powiedz układowi, aby ponownie obliczył układ, co jest równoznaczne z bezpośrednim ustawieniem ramek (w tym przypadku autolayout ustawi klatki):
Kompletny najprostszy przykład:
Dygresja
Istnieje opcjonalny krok zerowy - przed zmianą ograniczeń możesz zadzwonić,
self.view.layoutIfNeeded()
aby upewnić się, że punkt początkowy animacji pochodzi ze stanu ze stosowanymi starymi ograniczeniami (w przypadku, gdy wystąpiły inne zmiany ograniczeń, które nie powinny być uwzględnione w animacji ):UIViewPropertyAnimator
Ponieważ w iOS 10 mamy nowy mechanizm animacji -
UIViewPropertyAnimator
powinniśmy wiedzieć, że zasadniczo ten sam mechanizm ma do niego zastosowanie. Kroki są w zasadzie takie same:Ponieważ
animator
jest to enkapsulacja animacji, możemy zachować odniesienie do niej i wywołać ją później. Ponieważ jednak w bloku animacji po prostu mówimy autoukładowi, aby ponownie obliczył klatki, musimy zmienić ograniczenia przed wywołaniemstartAnimation
. Dlatego możliwe jest coś takiego:Kolejność zmiany wiązań i uruchomienia animatora jest ważna - jeśli po prostu zmienimy więzy i zostawimy naszego animatora na jakiś późniejszy moment, następny cykl przerysowania może wywołać ponowne obliczenie autoukładu, a zmiana nie będzie animowana.
Pamiętaj też, że pojedynczy animator nie nadaje się do ponownego użycia - po uruchomieniu nie można go „ponownie uruchomić”. Sądzę więc, że nie ma naprawdę dobrego powodu, aby trzymać animatora w pobliżu, chyba że użyjemy go do sterowania animacją interaktywną.
źródło
Scenorys, Kod, Wskazówki i kilka Gotch
Inne odpowiedzi są w porządku, ale ta uwypukla kilka dość ważnych problemów z animowaniem ograniczeń na ostatnim przykładzie. Przejrzałem wiele odmian, zanim zdałem sobie sprawę z następujących rzeczy:
Wprowadź ograniczenia, na które chcesz kierować, do zmiennych klasy, aby mieć mocne odniesienie. W Swift użyłem leniwych zmiennych:
Po niektórych eksperymentach zauważyłem, że MUSI uzyskać ograniczenie z widoku POWYŻEJ (czyli superview) dwa widoki, w których ograniczenie jest zdefiniowane. W poniższym przykładzie (zarówno MNGStarRating, jak i UIWebView to dwa typy elementów, między którymi tworzę ograniczenie, i są to widoki podrzędne w ramach self.view).
Łańcuch filtrów
Korzystam z metody filtrowania Swifta, aby oddzielić pożądane ograniczenie, które będzie służyć jako punkt przegięcia. Można się również komplikować, ale filtr robi tutaj niezłą robotę.
Animowanie ograniczeń za pomocą Swift
Zakładając, że utworzysz właściwość do filtrowania według dokładnych kryteriów i dojdziesz do określonego punktu przegięcia dla swojej animacji (oczywiście możesz również filtrować tablicę i przejść przez pętlę, jeśli potrzebujesz wielu ograniczeń):
…
Jakiś czas później...
Wiele złych zwrotów
Te notatki to tak naprawdę zestaw wskazówek, które sam dla siebie napisałem. Zrobiłem wszystkie zakazy osobiście i boleśnie. Mam nadzieję, że ten przewodnik może oszczędzić innym.
Uważaj na zPozycjonowanie. Czasami, gdy najwyraźniej nic się nie dzieje, należy ukryć niektóre inne widoki lub użyć debugera widoków, aby zlokalizować widok animowany. Znalazłem nawet przypadki, w których atrybut Runtime User Defined został utracony w pliku XML scenariusza i doprowadził do zasłonięcia widoku animowanego (podczas pracy).
Zawsze poświęć chwilę na przeczytanie dokumentacji (nowej i starej), szybkiej pomocy i nagłówków. Apple ciągle wprowadza wiele zmian, aby lepiej zarządzać ograniczeniami AutoLayout (patrz widoki stosów). Lub przynajmniej książka kucharska AutoLayout . Pamiętaj, że czasami najlepsze rozwiązania znajdują się w starszej dokumentacji / filmach.
Baw się z wartościami w animacji i rozważ użycie innych wariantów animateWithDuration.
Nie wpisuj konkretnych wartości układu jako kryteriów określania zmian w innych stałych, zamiast tego używaj wartości, które pozwalają określić lokalizację widoku.
CGRectContainsRect
jest jednym przykłademlet viewMargins = self.webview.layoutMarginsGuide
: na przykładSzybka próbka rozwiązań, których należy UNIKAĆ podczas używania Storyboardów
Jeśli zapomnisz jedną z tych wskazówek lub prostsze, na przykład, gdzie dodać układIfNeeded, najprawdopodobniej nic się nie wydarzy: W takim przypadku możesz mieć na wpół upieczone rozwiązanie:
Snippet z Przewodnika AutoLayout (zwróć uwagę, że drugi snippet dotyczy systemu OS X). BTW - O ile mi wiadomo, nie ma go w bieżącym przewodniku. Preferowane techniki nadal ewoluują.
Animowanie zmian dokonanych przez układ automatyczny
Jeśli potrzebujesz pełnej kontroli nad animowanymi zmianami wprowadzonymi przez Automatyczny układ, musisz wprowadzić zmiany ograniczenia programowo. Podstawowa koncepcja jest taka sama dla iOS i OS X, ale istnieje kilka drobnych różnic.
W aplikacji na iOS kod wyglądałby mniej więcej tak:
W systemie OS X użyj następującego kodu podczas korzystania z animacji z warstwami:
Jeśli nie korzystasz z animacji wspieranych warstwami, musisz animować stałą za pomocą animatora ograniczenia:
Dla tych, którzy lepiej się uczą, sprawdź ten wczesny film od Apple .
Zwrócić szczególną uwagę
Często w dokumentacji są małe notatki lub fragmenty kodu, które prowadzą do większych pomysłów. Na przykład dołączanie ograniczeń automatycznego układu do dynamicznych animatorów to świetny pomysł.
Powodzenia i niech Moc będzie z tobą.źródło
Szybkie rozwiązanie:
źródło
Roztwór roboczy 100% Swift 3.1
Przeczytałem wszystkie odpowiedzi i chcę udostępnić kod i hierarchię wierszy, których użyłem we wszystkich moich aplikacjach, aby animować je poprawnie. Niektóre rozwiązania tutaj nie działają, powinieneś je sprawdzić na wolniejszych urządzeniach, np. iPhone 5 w tym momencie.
źródło
Próbowałem animować Ograniczenia i nie było łatwo znaleźć dobre wytłumaczenie.
To, co mówią inne odpowiedzi, jest całkowicie prawdziwe: musisz zadzwonić do
[self.view layoutIfNeeded];
środkaanimateWithDuration: animations:
. Inną ważną kwestią jest jednak posiadanie wskaźników dla każdego,NSLayoutConstraint
który chcesz animować.Stworzyłem przykład w GitHub .
źródło
Działające i właśnie przetestowane rozwiązanie dla Swift 3 z Xcode 8.3.3:
Pamiętaj tylko, że self.calendarViewHeight jest ograniczeniem odnoszącym się do customView (CalendarView). Nazwałem .layoutIfNeeded () na self.view, a NIE na self.calendarView
Mam nadzieję, że to pomoże.
źródło
Istnieje artykuł na ten temat: http://weblog.invasivecode.com/post/42362079291/auto-layout-and-core-animation-auto-layout-was
W którym napisał tak:
Mam nadzieję, że to pomoże.
źródło
W kontekście animacji ograniczenia chciałbym wspomnieć o konkretnej sytuacji, w której animowałem ograniczenie natychmiast w powiadomieniu o otwarciu klawiatury.
Ograniczenie definiowało górną przestrzeń od pola tekstowego do góry kontenera. Po otwarciu klawiatury dzielę stałą przez 2.
Nie byłem w stanie uzyskać spójnej animacji płynnego wiązania bezpośrednio w powiadomieniu z klawiatury. Około połowy razy widok po prostu przeskoczyłby na nową pozycję - bez animacji.
Przyszło mi do głowy, że w wyniku otwarcia klawiatury mogą wystąpić dodatkowe układy. Dodanie prostego bloku dispatch_after z opóźnieniem 10 ms sprawiło, że animacja była uruchamiana za każdym razem - bez przeskakiwania.
źródło