Ich aktualisiere eine alte App mit einer AdBannerView
und wenn keine Anzeige vorhanden ist, wird sie vom Bildschirm verschoben. Wenn eine Anzeige vorhanden ist, wird sie auf dem Bildschirm angezeigt. Grundlegende Sachen.
Im alten Stil habe ich den Rahmen in einen Animationsblock gesetzt. Neuer Stil, ich habe eine IBOutlet
Einschränkung für das automatische Layout, die die Y
Position bestimmt, in diesem Fall den Abstand vom unteren Rand der Übersicht, und ändere die Konstante:
- (void)moveBannerOffScreen {
[UIView animateWithDuration:5 animations:^{
_addBannerDistanceFromBottomConstraint.constant = -32;
}];
bannerIsVisible = FALSE;
}
- (void)moveBannerOnScreen {
[UIView animateWithDuration:5 animations:^{
_addBannerDistanceFromBottomConstraint.constant = 0;
}];
bannerIsVisible = TRUE;
}
Und das Banner bewegt sich genau wie erwartet, aber keine Animation.
UPDATE: Ich habe WWDC 12 erneut gesehen, wie Best Practices für das Beherrschen des automatischen Layouts, das sich mit Animation befasst, besprochen wurden . Es wird erläutert, wie Einschränkungen mithilfe von CoreAnimation aktualisiert werden :
Ich habe es mit dem folgenden Code versucht, erhalte aber genau die gleichen Ergebnisse:
- (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;
}
Nebenbei bemerkt, ich habe mehrfach überprüft und dies wird auf dem Haupt- Thread ausgeführt.
Antworten:
Zwei wichtige Hinweise:
Sie müssen
layoutIfNeeded
innerhalb des Animationsblocks aufrufen . Apple empfiehlt, dass Sie es einmal vor dem Animationsblock aufrufen, um sicherzustellen, dass alle ausstehenden Layoutvorgänge abgeschlossen sindSie müssen es speziell in der übergeordneten Ansicht (z. B.
self.view
) aufrufen , nicht in der untergeordneten Ansicht, mit der die Einschränkungen verknüpft sind. Dadurch werden alle eingeschränkten Ansichten aktualisiert , einschließlich der Animation anderer Ansichten, die möglicherweise auf die Ansicht beschränkt sind, deren Einschränkung Sie geändert haben (z. B. wird Ansicht B am unteren Rand von Ansicht A angehängt, und Sie haben gerade den oberen Versatz von Ansicht A geändert, und Sie möchten Ansicht B. damit animieren)Versuche dies:
Ziel c
Swift 3
quelle
setNeedsLayout
anstattlayoutIfNeeded
. Ich bin etwas entsetzt darüber, wie viele Stunden ich damit verbracht habe, nicht zu bemerken, dass ich nur den falschen Methodennamen eingegeben habe.Ich freue mich über die Antwort, aber ich denke, es wäre schön, noch ein bisschen weiter zu gehen.
Die grundlegende Blockanimation aus der Dokumentation
Aber das ist wirklich ein sehr vereinfachtes Szenario. Was ist, wenn ich Subview-Einschränkungen über die
updateConstraints
Methode animieren möchte ?Ein Animationsblock, der die Methode updateConstraints der Unteransichten aufruft
Die updateConstraints-Methode wird in der UIView-Unterklasse überschrieben und muss am Ende der Methode super aufrufen.
Das AutoLayout-Handbuch lässt zu wünschen übrig, ist aber lesenswert. Ich selbst verwende dies als Teil einer
UISwitch
, die eine Unteransicht mit einem PaarUITextField
s mit einer einfachen und subtilen Kollapsanimation (0,2 Sekunden lang) umschaltet . Die Einschränkungen für die Unteransicht werden in den UpdateConstraints-Methoden der UIView-Unterklassen wie oben beschrieben behandelt.quelle
self.view
(und nicht in einer Unteransicht dieser Ansicht), ist ein AufrufupdateConstraintsIfNeeded
nicht erforderlich (dasetNeedsLayout
auchupdateConstraints
diese Ansicht ausgelöst wird ). Könnte für die meisten trivial sein, aber es war bis jetzt nicht für mich;)Im Allgemeinen müssen Sie nur die Einschränkungen aktualisieren und
layoutIfNeeded
den Animationsblock aufrufen . Dies kann entweder das Ändern der.constant
Eigenschaft vonNSLayoutConstraint
, das Hinzufügen von Einschränkungen zum Entfernen (iOS 7) oder das Ändern der.active
Eigenschaft von Einschränkungen (iOS 8 und 9) sein.Beispielcode:
Beispiel-Setup:
Kontroverse
Es gibt einige Fragen dazu, ob die Einschränkung vor oder innerhalb des Animationsblocks geändert werden soll (siehe vorherige Antworten).
Das Folgende ist ein Twitter-Gespräch zwischen Martin Pilkington, der iOS unterrichtet, und Ken Ferry, der Auto Layout geschrieben hat. Ken erklärt, dass das Ändern von Konstanten außerhalb des Animationsblocks derzeit möglicherweise funktioniert, jedoch nicht sicher ist und dass sie wirklich innerhalb des Animationsblocks geändert werden sollten . https://twitter.com/kongtomorrow/status/440627401018466305
Animation:
Beispielprojekt
Hier ist ein einfaches Projekt, das zeigt, wie eine Ansicht animiert werden kann. Es verwendet Objective C und animiert die Ansicht, indem die
.active
Eigenschaft mehrerer Einschränkungen geändert wird. https://github.com/shepting/SampleAutoLayoutAnimationquelle
quelle
Swift 4-Lösung
UIView.animate
Drei einfache Schritte:
Ändern Sie die Einschränkungen, z.
Sagen Sie dem Inhalt,
view
dass sein Layout verschmutzt ist und dass das Autolayout das Layout neu berechnen sollte:Weisen Sie das Layout im Animationsblock an, das Layout neu zu berechnen. Dies entspricht dem direkten Einstellen der Frames (in diesem Fall werden die Frames durch das automatische Layout festgelegt):
Vollständigstes einfachstes Beispiel:
Randnotiz
Es gibt einen optionalen 0. Schritt - bevor Sie die Einschränkungen ändern, die Sie möglicherweise aufrufen möchten,
self.view.layoutIfNeeded()
stellen Sie sicher, dass der Startpunkt für die Animation aus dem Status stammt, in dem alte Einschränkungen angewendet wurden (falls einige andere Einschränkungen geändert wurden, die nicht in die Animation aufgenommen werden sollten ):UIViewPropertyAnimator
Da wir mit iOS 10 einen neuen Animationsmechanismus haben -
UIViewPropertyAnimator
sollten wir wissen, dass im Grunde der gleiche Mechanismus für ihn gilt. Die Schritte sind grundsätzlich gleich:Da
animator
es sich um eine Kapselung der Animation handelt, können wir darauf verweisen und sie später aufrufen. Da wir im Animationsblock jedoch nur das Autolayout anweisen, die Frames neu zu berechnen, müssen wir die Einschränkungen vor dem Aufruf ändernstartAnimation
. Daher ist so etwas möglich:Die Reihenfolge des Änderns von Einschränkungen und des Startens eines Animators ist wichtig. Wenn wir nur die Einschränkungen ändern und unseren Animator für einen späteren Zeitpunkt verlassen, kann der nächste Neuzeichnungszyklus eine Neuberechnung des automatischen Layouts aufrufen und die Änderung wird nicht animiert.
Denken Sie auch daran, dass ein einzelner Animator nicht wiederverwendbar ist. Sobald Sie ihn ausgeführt haben, können Sie ihn nicht mehr "erneut ausführen". Ich denke, es gibt keinen guten Grund, den Animator in der Nähe zu halten, es sei denn, wir verwenden ihn zur Steuerung einer interaktiven Animation.
quelle
Storyboard, Code, Tipps und ein paar Fallstricke
Die anderen Antworten sind in Ordnung, aber diese zeigt einige ziemlich wichtige Fallstricke beim Animieren von Einschränkungen anhand eines aktuellen Beispiels. Ich habe viele Variationen durchlaufen, bevor mir Folgendes klar wurde:
Machen Sie die Einschränkungen, auf die Sie abzielen möchten, zu Klassenvariablen, um eine starke Referenz zu erhalten. In Swift habe ich faule Variablen verwendet:
Nach einigen Experimenten stellte ich fest, dass man die Einschränkung aus der Ansicht OBEN (auch bekannt als Übersicht) der beiden Ansichten erhalten muss, in denen die Einschränkung definiert ist. Im folgenden Beispiel (sowohl MNGStarRating als auch UIWebView sind die beiden Arten von Elementen, zwischen denen ich eine Einschränkung erstelle, und sie sind Unteransichten in self.view).
Filterverkettung
Ich nutze die Filtermethode von Swift, um die gewünschte Einschränkung zu trennen, die als Wendepunkt dient. Man könnte auch viel komplizierter werden, aber Filter macht hier einen guten Job.
Animieren von Einschränkungen mit Swift
Angenommen, Sie erstellen eine Eigenschaft zum Filtern nach genauen Kriterien und gelangen zu einem bestimmten Wendepunkt für Ihre Animation (natürlich können Sie auch nach einem Array filtern und eine Schleife durchführen, wenn Sie mehrere Einschränkungen benötigen):
....
Etwas später...
Die vielen falschen Wendungen
Diese Notizen sind wirklich eine Reihe von Tipps, die ich für mich selbst geschrieben habe. Ich habe alle Dinge persönlich und schmerzhaft getan. Hoffentlich kann dieser Leitfaden andere schonen.
Achten Sie auf zPositioning. Manchmal, wenn anscheinend nichts passiert, sollten Sie einige der anderen Ansichten ausblenden oder den Ansichtsdebugger verwenden, um Ihre animierte Ansicht zu finden. Ich habe sogar Fälle gefunden, in denen ein benutzerdefiniertes Laufzeitattribut in der XML-Datei eines Storyboards verloren ging und dazu führte, dass die animierte Ansicht (während der Arbeit) abgedeckt wurde.
Nehmen Sie sich immer eine Minute Zeit, um die Dokumentation (neu und alt), die Schnellhilfe und die Überschriften zu lesen. Apple nimmt ständig Änderungen vor, um die AutoLayout-Einschränkungen besser zu verwalten (siehe Stapelansichten). Oder zumindest das AutoLayout-Kochbuch . Denken Sie daran, dass die besten Lösungen manchmal in den älteren Dokumentationen / Videos enthalten sind.
Spielen Sie mit den Werten in der Animation und erwägen Sie die Verwendung anderer animateWithDuration-Varianten.
Codieren Sie bestimmte Layoutwerte nicht als Kriterien zum Bestimmen von Änderungen an anderen Konstanten, sondern verwenden Sie Werte, mit denen Sie den Speicherort der Ansicht bestimmen können.
CGRectContainsRect
ist ein Beispiellet viewMargins = self.webview.layoutMarginsGuide
: ist ein BeispielSchnelle Auswahl an Lösungen, die bei der Verwendung von Storyboards vermieden werden sollten
Wenn Sie einen dieser Tipps oder die einfacheren Tipps vergessen, z. B. wo das layoutIfNeeded hinzugefügt werden soll, passiert höchstwahrscheinlich nichts: In diesem Fall haben Sie möglicherweise eine halbherzige Lösung wie diese:
Snippet aus dem AutoLayout-Handbuch (beachten Sie, dass das zweite Snippet für die Verwendung von OS X vorgesehen ist). Übrigens - Soweit ich sehen kann, ist dies nicht mehr im aktuellen Handbuch enthalten. Die bevorzugten Techniken entwickeln sich weiter.
Animieren von Änderungen, die durch das automatische Layout vorgenommen wurden
Wenn Sie die vollständige Kontrolle über das Animieren von Änderungen benötigen, die von Auto Layout vorgenommen wurden, müssen Sie Ihre Einschränkungsänderungen programmgesteuert vornehmen. Das Grundkonzept ist für iOS und OS X gleich, es gibt jedoch einige geringfügige Unterschiede.
In einer iOS-App sieht Ihr Code folgendermaßen aus:
Verwenden Sie in OS X den folgenden Code, wenn Sie Animationen mit Ebenen verwenden:
Wenn Sie keine Animationen mit Ebenenunterstützung verwenden, müssen Sie die Konstante mit dem Animator der Einschränkung animieren:
Für diejenigen, die visuell besser lernen, sehen Sie sich dieses frühe Video von Apple an .
Pass gut auf
Oft gibt es in der Dokumentation kleine Notizen oder Codeteile, die zu größeren Ideen führen. Das Anhängen von Einschränkungen für das automatische Layout an dynamische Animatoren ist beispielsweise eine große Idee.
Viel Glück und möge die Macht mit dir sein.quelle
Schnelle Lösung:
quelle
Arbeitslösung 100% schnell 3.1
Ich habe alle Antworten gelesen und möchte den Code und die Hierarchie der Zeilen teilen, die ich in all meinen Anwendungen verwendet habe, um sie korrekt zu animieren. Einige Lösungen hier funktionieren nicht. Sie sollten sie derzeit auf langsameren Geräten, z. B. iPhone 5, überprüfen.
quelle
Ich habe versucht, Einschränkungen zu animieren, und es war nicht einfach, eine gute Erklärung zu finden.
Was andere Antworten sagen, ist völlig richtig: Sie müssen
[self.view layoutIfNeeded];
drinnen anrufenanimateWithDuration: animations:
. Der andere wichtige Punkt ist jedoch, Zeiger für jeden zu haben, denNSLayoutConstraint
Sie animieren möchten.Ich habe ein Beispiel in GitHub erstellt .
quelle
Funktionierende und gerade getestete Lösung für Swift 3 mit Xcode 8.3.3:
Denken Sie daran, dass self.calendarViewHeight eine Einschränkung ist, die auf eine benutzerdefinierte Ansicht (CalendarView) verweist. Ich habe .layoutIfNeeded () in self.view und NICHT in self.calendarView aufgerufen
Ich hoffe das hilft.
quelle
Es gibt einen Artikel darüber: http://weblog.invasivecode.com/post/42362079291/auto-layout-and-core-animation-auto-layout-was
In dem er so codierte:
Ich hoffe es hilft.
quelle
Im Zusammenhang mit der Einschränkungsanimation möchte ich eine bestimmte Situation erwähnen, in der ich eine Einschränkung sofort in einer Benachrichtigung mit Tastaturöffnung animiert habe.
Die Einschränkung definierte einen oberen Bereich von einem Textfeld bis zum oberen Rand des Containers. Beim Öffnen der Tastatur teile ich die Konstante einfach durch 2.
Ich konnte keine konsistente glatte Einschränkungsanimation direkt in der Tastaturbenachrichtigung erzielen. Etwa die Hälfte der Zeit würde die Ansicht einfach an ihre neue Position springen - ohne zu animieren.
Mir ist aufgefallen, dass durch das Öffnen der Tastatur möglicherweise zusätzliche Layouts erstellt werden. Durch Hinzufügen eines einfachen dispatch_after-Blocks mit einer Verzögerung von 10 ms wurde die Animation jedes Mal ausgeführt - kein Springen.
quelle