2008-11-17 11 views
46

Ich frage mich, wo die Callbacks (oder wenn es etwas gibt) für Animationen in einem CALayer. Insbesondere für implizite Animationen wie den Rahmen zu verändern, Position usw. In einem UIView, könnten Sie so etwas tun:Animation Ende Callback für CALayer?

[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 die setAnimationDidStopSelector ist, was ich für eine Animation in einem CALayer wollen. Gibt es so etwas?

TIA.

+0

Für alle hier googeln, ich habe unglaublich in einer modernen Antwort auf diese Frage stellen alte Frage! : O Search down to "2017 ..." – Fattie

Antwort

50

Ich beantwortete meine eigene Frage. Sie müssen eine Animation hinzufügen, mit CABasicAnimation wie so:

CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"frame"]; 
anim.fromValue = [NSValue valueWithCGRect:layer.frame]; 
anim.toValue = [NSValue valueWithCGRect:frame]; 
anim.delegate = self; 
[layer addAnimation:anim forKey:@"frame"]; 

und Umsetzung der Delegatmethode animationDidStop:finished: und Sie sollten gut zu gehen. Zum Glück existiert diese Funktionalität! : D

+2

Diese Antwort ist nützlich für die Informationen über Delegat, aber es hat einen großen Fehler - Sie können "Frame" nicht animieren, wie es eine abgeleitete Eigenschaft ist. http://developer.apple.com/library/mac/#qa/qa2008/qa1620.html – Michal

0

Sie können den Namen einer bestimmten Animation beim Einrichten des CAAnimation-Objekts festlegen. Vergleichen Sie in animationDiStop: finished einfach den Namen des bereitgestelltenAnimation-Objekts, um spezifische Funktionen basierend auf der Animation auszuführen.

+1

Es gibt keine Namenseigenschaft? – Andy

104

Sie könnten eine CATransaction verwenden, sie hat einen Completion-Block-Handler.

[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]; 
+15

Beachten Sie, dass es wichtig ist, den Abschlussblock VOR dem Hinzufügen der Animation zum Layer festzulegen. – Groot

+0

Dies ist nicht immer nützlich, weil Sie auch beim Entfernen der Animation aufgerufen werden, auch wenn sie nicht beendet wurde. –

8

Nur ein Hinweis für diejenigen, die diese Seite auf Google finden: Sie können wirklich den Job, indem Sie den „delegieren“ Eigentum Ihrer Animationsobjekt auf das Objekt erledigen, die die Benachrichtigung erhalten und die Umsetzung der „animationDidStop "Methode in der .m-Datei dieses Objekts. Ich habe es gerade ausprobiert und es funktioniert. Ich weiß nicht, warum Joe Blow gesagt hat, dass das nicht der richtige Weg ist.

+0

Versuchte alles von removeAllAnimations zu bestimmten CAAnimations mit dem setCompletionBlock und CATransation.begin und commit wie die Antwort von user3077725. Versuchte UIView.animateWIthDuration. Funktionierte nicht für eine einfache alpha und position.x Animation. Die Delegate-Methode war die einzige Sache, die richtig funktionierte. – KorinW

44

4 Stunden mit diesem Müll verschwendet, nur um ein Einblenden auszublenden. Beachten Sie den Kommentar im Code. Hier

[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]; 
+0

Ich vermute, dass Sie in Ihrer Ursache die Autoreverse-Eigenschaft hätten verwenden können, weil das, was Sie tun, im Grunde genommen die erste Animation umkehrt. – denis631

+0

Diese Antwort brachte mich zum Lachen! Ich war total dort und habe versucht, eine scheinbar kleine Sache für mehrere Stunden zu arbeiten ... ✊ –

29

ist eine Antwort in Swift 3.0 basierend auf bennythemink Lösung:

// 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() 
8

Für 2018 ...

Swift 4.

In der Praxis müssen Sie [weak self] oder Sie‘ in der Regel abstürzen.

func animeExample() { 

    CATransaction.begin() 

    let a = CABasicAnimation(keyPath: "fillColor") 
    a.fromValue, duration = ... etc etc 

    CATransaction.setCompletionBlock{ [weak self] in 
     self?.animeExample() 
    } 

    someLayer.add(a, forKey: nil) 
    CATransaction.commit() 
} 

Im Beispiel ruft es sich einfach selbst wieder an.

Natürlich können Sie jede Funktion aufrufen.


Hinweis: Wenn Sie gerade erst anfangen. Es ist daran zu erinnern, dass der "Schlüssel" (wie in add#forKey) irrelevant und selten verwendet wird. Setze es auf Null. Wenn Sie es aus irgendeinem Grund einstellen möchten, ist es "eine beliebige Zeichenfolge" (sagen wir Ihr Nickname). Die keyPath in der CABasicAnimation Aufruf ist die eigentliche "Sache, die Sie animieren", mit anderen Worten ist es buchstäblich eine Eigenschaft der Ebene (nur als String geschrieben).

1

In Swift 4+ ich habe gerade hinzugefügt delegate als

class CircleView: UIView,CAAnimationDelegate { 
... 

let animation = CABasicAnimation(keyPath: "strokeEnd") 
animation.delegate = self//Set delegate 

Animations Abschluss Rückruf -

func animationDidStop(_ anim: CAAnimation, finished flag: Bool) { 
    print("Animation END") 
    }