Ich frage mich, wo die Rückrufe für Animationen in einem CALayer sind (oder ob es irgendetwas gibt). Insbesondere für implizite Animationen wie das Ändern des Rahmens, der Position usw. In einer UIView können Sie Folgendes tun:
[UIView beginAnimations:@"SlideOut" context:nil];
[UIView setAnimationDuration:.3];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(animateOut:finished:context:)];
CGRect frame = self.frame;
frame.origin.y = 480;
self.frame = frame;
[UIView commitAnimations];
Insbesondere ist dies das, setAnimationDidStopSelector
was ich für eine Animation in einem CALayer möchte. Gibt es so etwas?
TIA.
iphone
core-animation
Jeffrey Forbes
quelle
quelle
Antworten:
Sie können eine CATransaction verwenden, die über einen Abschlussblock-Handler verfügt.
[CATransaction begin]; CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; [pathAnimation setDuration:1]; [pathAnimation setFromValue:[NSNumber numberWithFloat:0.0f]]; [pathAnimation setToValue:[NSNumber numberWithFloat:1.0f]]; [CATransaction setCompletionBlock:^{_lastPoint = _currentPoint; _currentPoint = CGPointMake(_lastPoint.x + _wormStepHorizontalValue, _wormStepVerticalValue);}]; [_pathLayer addAnimation:pathAnimation forKey:@"strokeEnd"]; [CATransaction commit];
quelle
Ich habe meine eigene Frage beantwortet. Sie müssen eine Animation
CABasicAnimation
wie folgt hinzufügen :CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"frame"]; anim.fromValue = [NSValue valueWithCGRect:layer.frame]; anim.toValue = [NSValue valueWithCGRect:frame]; anim.delegate = self; [layer addAnimation:anim forKey:@"frame"];
Wenn Sie die Delegate-Methode implementieren
animationDidStop:finished:
, sollten Sie bereit sein. Gott sei Dank existiert diese Funktionalität! : D.quelle
Hier ist eine Antwort in Swift 3.0, die auf der Lösung von bennythemink basiert:
// Begin the transaction CATransaction.begin() let animation = CABasicAnimation(keyPath: "strokeEnd") animation.duration = duration //duration is the number of seconds animation.fromValue = 0 animation.toValue = 1 animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) circleLayer.strokeEnd = 1.0 // Callback function CATransaction.setCompletionBlock { print("end animation") } // Do the actual animation and commit the transaction circleLayer.add(animation, forKey: "animateCircle") CATransaction.commit()
quelle
Für 2018 ...
Einfacher geht es nicht.
Vergiss das nicht
[weak self]
oder du wirst abstürzen.func animeExample() { CATransaction.begin() let a = CABasicAnimation(keyPath: "fillColor") a.fromValue, duration = ... etc etc CATransaction.setCompletionBlock{ [weak self] in self?.animeExample() self?.ringBell() print("again...") } someLayer.add(a, forKey: nil) CATransaction.commit() }
Im Beispiel ruft es sich einfach erneut auf.
Natürlich können Sie jede Funktion aufrufen.
Hinweise für alle, die noch keine Erfahrung mit iOS-Animationen haben:
Der "Schlüssel" (wie in
forKey
) ist irrelevant und wird selten verwendet . Setzen Sie es auf Null. Wenn Sie es einstellen möchten, setzen Sie es auf "beliebige Zeichenfolge".Der "keyPath" ist in der Tat das eigentliche "Ding, das Sie animieren" . Es ist buchstäblich eine Eigenschaft der Ebene wie "Deckkraft", "Hintergrundfarbe" usw., aber als Zeichenfolge geschrieben . (Sie können dort nicht einfach "alles, was Sie wollen" eingeben, es muss der Name einer tatsächlichen Eigenschaft der Ebene sein und es muss animierbar sein.)
Um es zu wiederholen: Der "Schlüssel" (selten verwendet - setzen Sie ihn einfach auf Null) und der "Schlüsselpfad" sind völlig unabhängig voneinander.
Sie sehen oft Beispielcode, in dem diese beiden verwechselt werden (dank der albernen Benennung), was alle möglichen Probleme verursacht.
Beachten Sie, dass Sie alternativ den Delegaten verwenden können, es jedoch viel einfacher ist, nur den Abschlussblock zu verwenden, da (A) er in sich geschlossen ist und überall verwendet werden kann und (B) Sie normalerweise mehr als einen Anime haben. In diesem Fall verwenden Sie den Delegierter ist langweilig.
quelle
[weak self]
Teil im Detail zu erklären ? Bei mir funktioniert es auch ohne.4 Stunden mit diesem Müll verschwendet, nur um ein Einblenden zu machen. Beachten Sie den Kommentar im Code.
[CATransaction begin]; CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"]; animation.duration = 0.3; animation.fromValue = [NSNumber numberWithFloat:0.0f]; animation.toValue = [NSNumber numberWithFloat:1.0f]; animation.removedOnCompletion = NO; animation.fillMode = kCAFillModeBoth; /// [box addAnimation:animation forKey:@"j"]; Animation will not work if added here. Need to add this only after the completion block. [CATransaction setCompletionBlock:^{ CABasicAnimation *animation2 = [CABasicAnimation animationWithKeyPath:@"opacity"]; animation2.duration = 0.3; animation2.beginTime = CACurrentMediaTime()+1; animation2.fromValue = [NSNumber numberWithFloat:1.0f]; animation2.toValue = [NSNumber numberWithFloat:0.0f]; animation2.removedOnCompletion = NO; animation2.fillMode = kCAFillModeBoth; [box addAnimation:animation2 forKey:@"k"]; }]; [box addAnimation:animation forKey:@"j"]; [CATransaction commit];
quelle
animation.removedOnCompletion = NO;
stattdessen nicht den Wert Ihrer Ebene festlegen, bevor Sie die Animation starten. Auf diese Weise bringen Sie Präsentation und Modellschicht durcheinander.Nur ein Hinweis für diejenigen, die diese Seite bei Google finden: Sie können die Aufgabe wirklich erledigen, indem Sie die Eigenschaft "delegieren" Ihres Animationsobjekts auf das Objekt setzen, das die Benachrichtigung erhält, und die Methode "animationDidStop" in der .m-Datei dieses Objekts implementieren Datei. Ich habe es gerade versucht und es funktioniert. Ich weiß nicht, warum Joe Blow gesagt hat, dass das nicht der richtige Weg ist.
quelle
In Swift 4+ habe ich gerade
delegate
als hinzugefügtclass CircleView: UIView,CAAnimationDelegate { ... let animation = CABasicAnimation(keyPath: "strokeEnd") animation.delegate = self//Set delegate
Rückruf zum Abschluss der Animation -
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) { print("Animation END") }
quelle
Swift 5.0
func blinkShadow(completion: @escaping (() -> Void)) { CATransaction.begin() let animation = CABasicAnimation(keyPath: "shadowRadius") animation.fromValue = layer.shadowRadius animation.toValue = 0.0 animation.duration = 0.1 animation.autoreverses = true CATransaction.setCompletionBlock(completion) layer.add(animation, forKey: nil) CATransaction.commit() }
quelle
Sie können den Namen einer bestimmten Animation festlegen, wenn Sie das CAAnimation-Objekt einrichten. Vergleichen Sie in animationDiStop: beendet einfach den Namen des bereitgestellten Animationsobjekts, um bestimmte Funktionen basierend auf der Animation auszuführen.
quelle
Für 2020 ...
ValueAnimator, aktualisieren Sie Ihre benutzerdefinierten Eigenschaften.
https://github.com/Only-IceSoul/ios-jjvalueanimator
class OnAnimationListener : AnimatorListener { weak var s : ViewController? init(_ ins: ViewController) { s = ins } func onAnimationStart(_ animation: Animator) {} func onAnimationEnd(_ animation: Animator) { print("end") s?.label.text = "end" } func onAnimationCancel(_ animation: Animator) {} func onAnimationRepeat(_ animation: Animator) {} }
quelle
Ich habe eine Erweiterung zu CAAnimation geschrieben, die Ihnen einen Anfang und einen Abschluss bietet, da ich es satt hatte, den Delegaten zu implementieren, insbesondere für mehrere Animationen, bei denen Sie schreckliche Dinge tun müssten, z. B. den Schlüssel der Animation verwenden, um zu sehen, welche Animation vorhanden ist den Delegierten anrufen - macht so etwas wirklich einfach.
Es ist auf GitHub - Animationsaktionen
Hoffentlich nützlich für jemanden!
quelle