¿Cómo cancelar la animación basada en bloques de UIView?

86

He buscado un montón de cosas SO y en las referencias de Apple, pero todavía no puedo gestionar mi problema.

Lo que tengo:

  1. Una pantalla con 2 UIImageViewsy 2 UIButtons conectados a ellos
  2. 2 tipos de animación:
    1. Ampliación y reducción de cada imagen, una tras otra, solo una vez en viewDidLoad
    2. Cuando se presiona un botón (un botón personalizado oculto "dentro" de cada uno UIImageView), se activa la animación correspondiente UIImageView, solo uno, no ambos (también escala hacia arriba y luego hacia abajo).
    3. Mientras escribo para iOS4 +, ¡me han dicho que use animaciones basadas en bloques!

Lo que necesito:

¿Cómo cancelo una animación en ejecución? Me las arreglé para cancelar después de todos menos el último ...: /

Aquí está mi fragmento de código:

[UIImageView animateWithDuration:2.0 
                               delay:0.1 
                             options:UIViewAnimationOptionAllowUserInteraction 
                          animations:^{
        isAnimating = YES;
        self.bigLetter.transform = CGAffineTransformScale(self.bigLetter.transform, 2.0, 2.0);
    } completion:^(BOOL finished){
        if(! finished) return;
        [UIImageView animateWithDuration:2.0 
                                   delay:0.0 
                                 options:UIViewAnimationOptionAllowUserInteraction 
                              animations:^{
            self.bigLetter.transform = CGAffineTransformScale(self.bigLetter.transform, 0.5, 0.5);
        } completion:^(BOOL finished){
            if(! finished) return;
            [UIImageView animateWithDuration:2.0 
                                       delay:0.0 
                                     options:UIViewAnimationOptionAllowUserInteraction 
                                  animations:^{
                self.smallLetter.transform = CGAffineTransformScale(self.smallLetter.transform, 2.0, 2.0);
            } completion:^(BOOL finished){
                if(! finished) return;
                [UIImageView animateWithDuration:2.0 
                                           delay:0.0 
                                         options:UIViewAnimationOptionAllowUserInteraction 
                                      animations:^{
                    self.smallLetter.transform = CGAffineTransformScale(self.smallLetter.transform, 0.5, 0.5);
                }
                                      completion:^(BOOL finished){
                                          if (!finished) return;
                                          //block letter buttons
                                          [self.bigLetterButton setUserInteractionEnabled:YES];
                                          [self.smallLetterButton setUserInteractionEnabled:YES];
                                          //NSLog(@"vieDidLoad animations finished");
                                      }];
            }];
        }];
    }];

De alguna manera el smallLetter UIImageViewno funciona correctamente, porque cuando se presiona (a través del botón) bigLetterse cancelan las animaciones correctamente ...

EDITAR: He usado esta solución, pero todavía tengo problemas con la reducción smallLetter UIImageView, sin cancelar en absoluto ... solución

EDIT2: agregué esto al comienzo de los métodos next / prev:

- (void)stopAnimation:(UIImageView*)source {
    [UIView animateWithDuration:0.01
                          delay:0.0 
                        options:(UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionAllowUserInteraction)
                     animations:^ {
                         source.transform = CGAffineTransformIdentity;
                     }
                     completion:NULL
     ];
}

el problema permanece ...: / no tengo idea de cómo interrumpir la última animación de las letras en la cadena de animación

Raistlin
fuente
Oye, creo que la respuesta de Hari Kunwar debería aceptarse ahora.
marczellm
En estos días, debe usar UIViewPropertyAnimator; también es tremendamente más fácil.
Fattie

Respuestas:

151

Puede detener todas las animaciones en una vista llamando a:

[view.layer removeAllAnimations];

(Deberá importar el marco QuartzCore para llamar a métodos en view.layer).

Si desea detener una animación específica, no todas las animaciones, lo mejor que puede hacer es usar CAAnimations explícitamente en lugar de los métodos de ayuda de animación UIView, entonces tendrá un control más granular y podrá detener las animaciones explícitamente por su nombre.

La documentación de Apple Core Animation se puede encontrar aquí:

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreAnimation_guide/CreatingBasicAnimations/CreatingBasicAnimations.html

Nick Lockwood
fuente
10
Solo quiero agregar, en mi propia observación, animateWithDuration posterior ya no funciona después de llamar a removeAllAnimations. Esto es para hacer paginación y tirar para actualizar los controles, tal vez alguien más podría observar algo diferente. Termino usando CABasicAnimation y llamando a [myView.layer removeAnimationForKey: @ "animationKey"];
Zhang
Gracias por el consejo @Nick: solo un aviso de que el enlace ya no parece ser compatible, prueba este en su lugar: developer.apple.com/library/ios/documentation/Cocoa/Conceptual/…
trdavidson
52

Para iOS 10, use UIViewPropertyAnimator para animar. Proporciona métodos para iniciar, detener y pausar animaciones de UIView.

 let animator = UIViewPropertyAnimator(duration: 2.0, curve: .easeOut){
        self.view.alpha = 0.0
 }
 // Call this to start animation.
 animator.startAnimation()

 // Call this to stop animation.
 animator.stopAnimation(true)
Hari Kunwar
fuente
3

Agregaría a la respuesta de Nick que para hacer que removeAllAnimations sea suave, la próxima idea sea muy útil.

[view.layer removeAllAnimations];
[UIView transitionWithView:self.redView
                  duration:1.0f options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
                      [view.layer displayIfNeeded];
                  } completion:nil];
Gaston Morixe
fuente
0

Puedes probar esto (en Swift):

UIView.setAnimationsEnabled(false)
UIView.setAnimationsEnabled(true)

Nota: puede poner código entre esas dos llamadas si es necesario, por ejemplo:

UIView.setAnimationsEnabled(false)
aview.layer.removeAllAnimations() // remove layer based animations e.g. aview.layer.opacity
UIView.setAnimationsEnabled(true)
iAmcR
fuente