Ich hatte ein Problem mit einer Reihe überlappender CATransition / CAAnimation-Sequenzen, die ich alle ausführen musste, um benutzerdefinierte Vorgänge auszuführen, wenn die Animationen gestoppt wurden, aber ich wollte nur einen Delegaten-Handler für animationDidStop.
Ich hatte jedoch ein Problem, es schien keine Möglichkeit zu geben, jede CATransition / CAAnimation im animationDidStop-Delegaten eindeutig zu identifizieren.
Ich habe dieses Problem über das Schlüssel- / Wertesystem gelöst, das im Rahmen von CAAnimation verfügbar gemacht wurde.
Wenn Sie Ihre Animation starten, verwenden Sie die setValue-Methode in CATransition / CAAnimation, um Ihre Bezeichner und Werte festzulegen, die beim Auslösen von animationDidStop verwendet werden sollen:
-(void)volumeControlFadeToOrange
{
CATransition* volumeControlAnimation = [CATransition animation];
[volumeControlAnimation setType:kCATransitionFade];
[volumeControlAnimation setSubtype:kCATransitionFromTop];
[volumeControlAnimation setDelegate:self];
[volumeControlLevel setBackgroundImage:[UIImage imageNamed:@"SpecialVolume1.png"] forState:UIControlStateNormal];
volumeControlLevel.enabled = true;
[volumeControlAnimation setDuration:0.7];
[volumeControlAnimation setValue:@"Special1" forKey:@"MyAnimationType"];
[[volumeControlLevel layer] addAnimation:volumeControlAnimation forKey:nil];
}
- (void)throbUp
{
doThrobUp = true;
CATransition *animation = [CATransition animation];
[animation setType:kCATransitionFade];
[animation setSubtype:kCATransitionFromTop];
[animation setDelegate:self];
[hearingAidHalo setBackgroundImage:[UIImage imageNamed:@"m13_grayglow.png"] forState:UIControlStateNormal];
[animation setDuration:2.0];
[animation setValue:@"Throb" forKey:@"MyAnimationType"];
[[hearingAidHalo layer] addAnimation:animation forKey:nil];
}
In Ihrem animationDidStop-Delegaten:
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag{
NSString* value = [theAnimation valueForKey:@"MyAnimationType"];
if ([value isEqualToString:@"Throb"])
{
//... Your code here ...
return;
}
if ([value isEqualToString:@"Special1"])
{
//... Your code here ...
return;
}
//Add any future keyed animation operations when the animations are stopped.
}
Der andere Aspekt ist, dass Sie den Status im Schlüsselwertpaarungssystem beibehalten können, anstatt ihn in Ihrer Delegatenklasse speichern zu müssen. Je weniger Code, desto besser.
Lesen Sie unbedingt die Apple-Referenz zur Codierung von Schlüsselwertpaaren .
Gibt es bessere Techniken für die CAAnimation / CATransition-Identifizierung im animationDidStop-Delegaten?
Danke, - Batgar
quelle
CAAnimation
‚sdelegate
stark, so dass Sie es einstellen können müssen, umnil
zu vermeiden Zyklen zu behalten!Antworten:
Batgars Technik ist zu kompliziert. Nutzen Sie den forKey-Parameter in addAnimation. Es war genau für diesen Zweck gedacht. Nehmen Sie einfach den Aufruf von setValue heraus und verschieben Sie die Schlüsselzeichenfolge in den Aufruf von addAnimation. Beispielsweise:
In Ihrem animationDidStop-Rückruf können Sie dann Folgendes tun:
quelle
anim.removedOnCompletion = NO;
, dass es noch existiert, wenn-animationDidStop:finished:
es aufgerufen wird.Ich habe mir gerade einen noch besseren Weg ausgedacht, um den Abschlusscode für CAAnimations zu erstellen:
Ich habe ein typedef für einen Block erstellt:
Und ein Schlüssel, mit dem ich einer Animation einen Block hinzufüge:
Wenn ich dann nach Abschluss einer CAAnimation einen Animationsabschlusscode ausführen möchte, setze ich mich als Delegat der Animation und füge der Animation mit setValue: forKey: einen Codeblock hinzu.
Dann implementiere ich eine animationDidStop: finish: -Methode, die am angegebenen Schlüssel nach einem Block sucht und ihn ausführt, wenn er gefunden wird:
Das Schöne an diesem Ansatz ist, dass Sie den Bereinigungscode an derselben Stelle schreiben können, an der Sie das Animationsobjekt erstellen. Besser noch, da der Code ein Block ist, hat er Zugriff auf lokale Variablen in dem umschließenden Bereich, in dem er definiert ist. Sie müssen sich nicht mit dem Einrichten von userInfo-Wörterbüchern oder anderem Unsinn herumschlagen und müssen keine ständig wachsende animationDidStop: finish: -Methode schreiben, die immer komplexer wird, wenn Sie verschiedene Arten von Animationen hinzufügen.
Um ehrlich zu sein, sollte in CAAnimation eine Eigenschaft für den Abschlussblock integriert sein und Systemunterstützung für den automatischen Aufruf, falls eine angegeben ist. Der obige Code bietet Ihnen jedoch dieselbe Funktionalität mit nur wenigen Zeilen zusätzlichen Codes.
quelle
theBlock();
, und ich glaube, das liegt daran, dass der Bereich des Blocks zerstört wurde.Der zweite Ansatz funktioniert nur, wenn Sie explizit festlegen, dass Ihre Animation nach Abschluss nicht entfernt wird, bevor Sie sie ausführen:
Wenn Sie dies nicht tun, wird Ihre Animation vor Abschluss entfernt, und der Rückruf findet sie nicht im Wörterbuch.
quelle
Alle anderen Antworten sind viel zu kompliziert! Warum fügen Sie nicht einfach Ihren eigenen Schlüssel hinzu, um die Animation zu identifizieren?
Diese Lösung ist sehr einfach. Sie müssen lediglich einen eigenen Schlüssel zur Animation hinzufügen (in diesem Beispiel animationID).
Fügen Sie diese Zeile ein, um die Animation1 zu identifizieren :
und dies, um animation2 zu identifizieren :
Testen Sie es so:
Es sind keine Instanzvariablen erforderlich :
quelle
[animation valueForKey:@"animationID"]
Um zu verdeutlichen, was von oben impliziert wird (und was mich nach ein paar verschwendeten Stunden hierher gebracht hat): Erwarten Sie nicht, dass das ursprüngliche Animationsobjekt, das Sie zugewiesen haben, an Sie zurückgegeben wird
Wenn die Animation beendet ist,
[CALayer addAnimation:forKey:]
wird eine Kopie Ihrer Animation erstellt.Sie können sich darauf verlassen, dass die Schlüsselwerte, die Sie Ihrem Animationsobjekt gegeben haben, im Replikat-Animationsobjekt, das mit der
animationDidStop:finished:
Nachricht übergeben wurde, immer noch einen äquivalenten Wert (aber nicht unbedingt eine Zeigeräquivalenz) aufweisen . Wie oben erwähnt, verwenden Sie KVC und Sie erhalten ausreichend Spielraum zum Speichern und Abrufen des Status.quelle
[animation setValue:@"myanim" forKey:@"name"]
festlegen und sogar die Ebene festlegen, mit der animiert werden soll[animation setValue:layer forKey:@"layer"]
. Diese Werte können dann innerhalb der Delegatmethoden abgerufen werden.valueForKey:
kehrtnil
für mich zurück, eine Idee warum?Ich kann meistens objc Antworten sehen, die ich für Swift 2.3 basierend auf der besten Antwort oben machen werde.
Zunächst einmal ist es gut, alle diese Schlüssel in einer privaten Struktur zu speichern, damit sie typsicher ist. Wenn Sie sie in Zukunft ändern, werden Sie keine nervigen Fehler bekommen, nur weil Sie vergessen haben, sie überall im Code zu ändern:
Wie Sie sehen können, habe ich die Namen der Variablen / Animationen geändert, damit es klarer wird. Setzen Sie nun diese Tasten, wenn die Animation erstellt wird.
(...)
Behandeln Sie dann endlich den Delegaten, wenn die Animation stoppt
quelle
IMHO mit Apples Schlüsselwert ist die elegante Art, dies zu tun: Es ist speziell dazu gedacht, anwendungsspezifische Daten zu Objekten hinzuzufügen.
Eine andere, viel weniger elegante Möglichkeit besteht darin, Verweise auf Ihre Animationsobjekte zu speichern und einen Zeigervergleich durchzuführen, um sie zu identifizieren.
quelle
Damit ich überprüfen kann, ob 2 CABasicAnimation-Objekte dieselbe Animation sind, verwende ich die keyPath-Funktion, um genau das zu tun.
if ([animationA keyPath] == [animationB keyPath])
quelle
Ich verwende gerne
setValue:forKey
: Um einen Verweis auf die Ansicht zu behalten, die ich animiere, ist es sicherer, als zu versuchen, die Animation anhand der ID eindeutig zu identifizieren, da dieselbe Art von Animation verschiedenen Ebenen hinzugefügt werden kann.Diese beiden sind gleichwertig:
mit diesem:
und in der Delegate-Methode:
quelle
Xcode 9 Swift 4.0
Mithilfe von Schlüsselwerten können Sie eine Animation verknüpfen, die Sie der in der delegate-Methode animationDidStop zurückgegebenen Animation hinzugefügt haben.
Deklarieren Sie ein Wörterbuch, das alle aktiven Animationen und zugehörigen Vervollständigungen enthält:
Wenn Sie Ihre Animation hinzufügen, legen Sie einen Schlüssel dafür fest:
In animationDidStop geschieht die Magie:
quelle