2008-11-17 17 views
46

Me pregunto dónde están las devoluciones de llamada (o si hay algo) para las animaciones en un CALayer. En concreto, para las animaciones implícitas como la alteración de la estructura, posición, etc. En una UIView, se podría hacer algo como esto:Animation End Callback para 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]; 

En concreto, el setAnimationDidStopSelector es lo que yo quiero para una animación en un CALayer. ¿Hay algo por el estilo?

TIA.

+0

Para cualquiera googlear aquí, he puesto en una respuesta moderna a este increíblemente vieja pregunta! : O Buscar en "2017 ..." – Fattie

Respuesta

50

Respondí mi propia pregunta. Hay que añadir una animación usando CABasicAnimation así:

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

y poner en práctica el método delegado animationDidStop:finished: y usted debe ser bueno para ir. ¡Gracias a Dios que esta funcionalidad existe! : D

+2

Esta respuesta es útil para la información sobre el delegado, pero tiene un gran defecto: no se puede animar el "marco" ya que es una propiedad derivada. http://developer.apple.com/library/mac/#qa/qa2008/qa1620.html – Michal

0

Puede configurar el nombre de una animación determinada al configurar el objeto CAAnimation. En animationDiStop: finalizado, simplemente compare el nombre del objeto Animation proporcionado para realizar su funcionalidad específica basada en la animación.

+1

No hay nombre de propiedad? – Andy

104

Puede usar un CATransaction, tiene un controlador de bloques de finalización.

[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

Tenga en cuenta que es importante establecer el bloque de finalización ANTES de agregar la animación a la capa. – Groot

+0

Esto no siempre es útil porque también se te llama cuando eliminas la animación aunque no haya terminado. –

8

Sólo una nota para aquellos que encuentran esta página en Google: Usted puede realmente hacer el trabajo estableciendo la propiedad "delegado" de su objeto de animación para el objeto que va a recibir la notificación y la aplicación de la "animationDidStop "método en el archivo .m de ese objeto. Lo intenté y funciona. No sé por qué Joe Blow dijo que esa no era la forma correcta.

+0

Probé todo, desde removeAllAnimations hasta CAAnimations específicas con setCompletionBlock y CATransation.begin y confirmo como la respuesta del usuario3077725. Intentó UIView.animateWIthDuration. No funcionó para una simple animación alpha y position.x. El método delegado fue lo único que funcionó correctamente. – KorinW

44

Perdió 4 horas con esta basura, solo para hacer un fundido en el fundido de salida. Tenga en cuenta el comentario en el código.

[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

Supongo que en su causa podría haber usado la propiedad de autoreverse, porque lo que está haciendo básicamente es invertir la primera animación. – denis631

+0

¡Esta respuesta me hizo reír! He estado totalmente allí tratando de hacer que algo aparentemente pequeño funcione durante varias horas ... ✊ –

29

Aquí es una respuesta en Swift 3.0 basado en la solución de bennythemink:

// 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

Para 2018 ...

Swift 4.

En la práctica necesita [weak self] o' Por lo general, se cuelga.

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() 
} 

En el ejemplo, simplemente se llama de nuevo.

Por supuesto, puede llamar a cualquier función.


Nota: si apenas está comenzando. Vale la pena recordar que la "clave" (como en add#forKey) es irrelevante y raramente utilizada. Ponlo en cero. Si por alguna razón desea establecerlo, es "cualquier cadena" (por ejemplo, su apodo). El keyPath en la llamada CABasicAnimation es la "cosa que está animando" en realidad, en otras palabras, es literalmente una propiedad de la capa (simplemente escrita como una cadena).

1

En Swift 4+ i acaba de añadir delegate como

class CircleView: UIView,CAAnimationDelegate { 
... 

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

Animación finalización de devolución de llamada -

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