¿Cancelar una animación UIView?

¿Es posible cancelar una animación UIView mientras está en progreso? ¿O tendría que bajar al nivel CA?

es decir, he hecho algo como esto (tal vez establecer una acción de animación final también):

 [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:duration]; [UIView setAnimationCurve: UIViewAnimationCurveLinear]; // other animation properties // set view properties [UIView commitAnimations]; 

Pero antes de que la animación se complete y recibo el evento de animación finalizada, quiero cancelarlo (abreviarlo). es posible? Buscar en Google encuentra a algunas personas que hacen la misma pregunta sin respuestas, y una o dos personas especulan que no se puede hacer.

La forma en que lo hago es crear una nueva animación para su punto final. Establezca una duración muy corta y asegúrese de utilizar el método +setAnimationBeginsFromCurrentState: para comenzar desde el estado actual. Cuando lo configura en SÍ, la animación actual se acorta. Se ve algo como esto:

 [UIView beginAnimations:nil context:NULL]; [UIView setAnimationBeginsFromCurrentState:YES]; [UIView setAnimationDuration:0.1]; [UIView setAnimationCurve: UIViewAnimationCurveLinear]; // other animation properties // set view properties [UIView commitAnimations]; 

Utilizar:

 #import  ....... [myView.layer removeAllAnimations]; 

La forma más simple de detener todas las animaciones en una vista particular, de inmediato , es esta:

Enlace el proyecto a QuartzCore.framework. Al comienzo de tu código:

 #import  

Ahora, cuando desee detener todas las animaciones en una vista muerta en sus pistas, diga esto:

 [CATransaction begin]; [theView.layer removeAllAnimations]; [CATransaction commit]; 

La línea del medio funcionaría por sí misma, pero hay un retraso hasta que termine el runloop (el “momento de redibujar”). Para evitar ese retraso, ajuste el comando en un bloque de transacción explícito como se muestra. Esto funciona siempre que no se hayan realizado otros cambios en esta capa en el runloop actual.

En iOS 4 y UIViewAnimationOptionBeginFromCurrentState , use la opción UIViewAnimationOptionBeginFromCurrentState en la segunda animación para cortar la primera animación corta.

Como ejemplo, suponga que tiene una vista con un indicador de actividad. Desea desvanecerse en el indicador de actividad mientras comienza una actividad que potencialmente consume mucho tiempo y desaparecer cuando finaliza la actividad. En el código siguiente, la vista con el indicador de actividad se llama activityView .

 - (void)showActivityIndicator { activityView.alpha = 0.0; activityView.hidden = NO; [UIView animateWithDuration:0.5 animations:^(void) { activityView.alpha = 1.0; }]; - (void)hideActivityIndicator { [UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void) { activityView.alpha = 0.0; } completion:^(BOOL completed) { if (completed) { activityView.hidden = YES; } }]; } 

Para cancelar una animación, simplemente necesita establecer la propiedad que se está animando actualmente, fuera de la animación de UIView. Eso detendrá la animación donde sea que esté, y UIView saltará a la configuración que acaba de definir.

Perdón por resucitar esta respuesta, pero en iOS 10 las cosas cambiaron un poco, y ahora es posible cancelar y ¡incluso puedes cancelar con gracia!

¡Después de iOS 10 puedes cancelar animaciones con UIViewPropertyAnimator !

 UIViewPropertyAnimator(duration: 2, dampingRatio: 0.4, animations: { view.backgroundColor = .blue }) animator.stopAnimation(true) 

Si pasa true, cancela la animación y se detiene justo donde la canceló. El método de finalización no se llamará. Sin embargo, si pasa falsa usted es responsable de terminar la animación:

 animator.finishAnimation(.start) 

Puede finalizar su animación y mantenerse en el estado actual (.corrent) o ir al estado inicial (.start) o al estado final (.end)

Por cierto, incluso puedes pausar y reiniciar más tarde …

 animator.pauseAnimation() animator.startAnimation() 

Nota: Si no desea una cancelación abrupta, puede invertir su animación o incluso cambiar su animación después de pausarla.

Si está animando una restricción al cambiar la constante en lugar de una propiedad de vista, ninguno de los otros métodos funciona en iOS 8.

Ejemplo de animación:

 self.constraint.constant = 0; [self.view updateConstraintsIfNeeded]; [self.view layoutIfNeeded]; [UIView animateWithDuration:1.0f delay:0.0f options:UIViewAnimationOptionCurveLinear animations:^{ self.constraint.constant = 1.0f; [self.view layoutIfNeeded]; } completion:^(BOOL finished) { }]; 

Solución:

Debe eliminar las animaciones de las capas de cualquier vista que se vean afectadas por el cambio de restricción y sus subcapas.

 [self.constraintView.layer removeAllAnimations]; for (CALayer *l in self.constraintView.layer.sublayers) { [l removeAllAnimations]; } 

Si solo quieres pausar / detener la animación sin problemas

 self.yourView.layer.speed = 0; 

Fuente: Cómo pausar la animación de un árbol de capas

Ninguno de los anteriores me lo resolvió, pero esto me ayudó: la animación de UIView establece la propiedad inmediatamente y luego la anima. Detiene la animación cuando la capa de presentación coincide con el modelo (la propiedad set).

Resolví mi problema, que era “Quiero animar desde donde pareces que apareces” (“tú”, es decir, la vista). Si quieres ESO, entonces:

  1. Añadir QuartzCore.
  2. CALayer * pLayer = theView.layer.presentationLayer;

establecer la posición a la capa de presentación

Uso algunas opciones, como UIViewAnimationOptionOverrideInheritedDuration

Pero como la documentación de Apple es vaga, no sé si realmente anula las otras animaciones cuando se usa, o simplemente restablece los temporizadores.

 [UIView animateWithDuration:blah... options: UIViewAnimationOptionBeginFromCurrentState ... animations: ^ { theView.center = CGPointMake( pLayer.position.x + YOUR_ANIMATION_OFFSET, pLayer.position.y + ANOTHER_ANIMATION_OFFSET); //this only works for translating, but you get the idea if you wanna flip and scale it. } completion: ^(BOOL complete) {}]; 

Y esa debería ser una solución decente por ahora.

 [UIView setAnimationsEnabled:NO]; // your code here [UIView setAnimationsEnabled:YES]; 

Tengo el mismo problema; las API no tienen nada para cancelar algunas animaciones específicas. los

+ (void)setAnimationsEnabled:(BOOL)enabled

deshabilita TODAS las animaciones, y por lo tanto no funciona para mí. Hay dos soluciones:

1) haz que tu objeto animado sea una subvista. Luego, cuando desee cancelar las animaciones para esa vista, elimine la vista u ocúltela. Muy simple, pero necesita recrear la subvista sin animaciones si necesita mantenerla a la vista.

2) repite solo el anim y crea un selector de delegates para reiniciar el anim si es necesario, como este:

 -(void) startAnimation { NSLog(@"startAnim alpha:%f", self.alpha); [self setAlpha:1.0]; [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:1.0]; [UIView setAnimationRepeatCount:1]; [UIView setAnimationRepeatAutoreverses:YES]; [UIView setAnimationDelegate:self]; [UIView setAnimationDidStopSelector:@selector(pulseAnimationDidStop:finished:context:)]; [self setAlpha:0.1]; [UIView commitAnimations]; } - (void)pulseAnimationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context { if(hasFocus) { [self startAnimation]; } else { self.alpha = 1.0; } } -(void) setHasFocus:(BOOL)_hasFocus { hasFocus = _hasFocus; if(hasFocus) { [self startAnimation]; } } 

El problema con 2) es que siempre hay demora para detener el anim mientras termina el ciclo de animación actual.

Espero que esto ayude.

Incluso si cancela la animación de la forma en que se realizó la animación, didStopSelector aún se ejecuta. Entonces, si tiene estados lógicos en su aplicación impulsados ​​por animaciones, tendrá problemas. Por esta razón, con las formas descritas anteriormente, utilizo la variable de contexto de UIView animaciones de UIView . Si pasa el estado actual de su progtwig por el parámetro de contexto a la animación, cuando la animación se detiene, su función didStopSelector puede decidir si debe hacer algo o simplemente devolver basándose en el estado actual y el valor de estado pasado como contexto.

 CALayer * pLayer = self.layer.presentationLayer; [UIView setAnimationBeginsFromCurrentState:YES]; [UIView animateWithDuration:0.001 animations:^{ self.frame = pLayer.frame; }]; 

Para pausar una animación sin revertir el estado a original o final:

 CFTimeInterval paused_time = [myView.layer convertTime:CACurrentMediaTime() fromLayer:nil]; myView.layer.speed = 0.0; myView.layer.timeOffset = paused_time; 

Versión rápida de la solución de Stephen Darlington

 UIView.beginAnimations(nil, context: nil) UIView.setAnimationBeginsFromCurrentState(true) UIView.setAnimationDuration(0.1) // other animation properties // set view properties UIView.commitAnimations()