Pregunta

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

es decir. Yo he hecho algo como esto (tal vez el establecimiento de 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 la animación completa y consigo el evento de animación terminado, quiero cancelarlo (abreviadora). es posible? Alrededor de google encuentra a unas pocas personas la misma pregunta sin respuesta -. Y una o dos personas que especulan que no se puede hacer

¿Fue útil?

Solución

La manera de hacerlo es crear una nueva animación a su punto final. Establecer una duración muy corta y asegúrese de usar el método +setAnimationBeginsFromCurrentState: que empezar desde el estado actual. Cuando se establece en YES, la animación actual se corta. Es como la siguiente:

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

// set view properties

[UIView commitAnimations];

Otros consejos

Uso:

#import <QuartzCore/QuartzCore.h>

.......

[myView.layer removeAllAnimations];

La manera más sencilla para detener todos animaciones en una visión particular, inmediatamente , es la siguiente:

Enlace del proyecto a QuartzCore.framework. Al comienzo de su código:

#import <QuartzCore/QuartzCore.h>

Ahora, cuando se desea detener todas las animaciones en una vista de muertos en sus pistas, decir lo siguiente:

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

La línea media podría funcionar por sí mismo, pero hay un retraso hasta que termine el Runloop (el "redibujar momento"). Para evitar este retraso, envuelva el comando en un bloque de transacción explícita como se muestra. Estos trabajos previstos otros cambios se han realizado en esta capa en el runloop actual.

En iOS 4 y mayor, utilizar la opción UIViewAnimationOptionBeginFromCurrentState en el segundo animación para cortar la primera animación corto.

A modo de ejemplo, supongamos que tiene una vista con un indicador de actividad. Quiera realizar el fundido en el indicador de actividad, mientras que algunos pueden llevar un tiempo que consume la actividad comienza, y se desvanecen a cabo una vez finalizada la actividad. En el código de abajo, la vista con el indicador de la actividad en que 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 sólo hay que establecer la propiedad que está siendo animado, fuera de la animación UIView. Que detenga la animación dondequiera que sea, y la UIView saltará a la configuración que acaba de definir.

Lo sentimos resucitar esta respuesta, pero en iOS 10 cosas cambiaron un poco, y ahora la cancelación es posible e incluso se puede cancelar con gracia!

Después de 10 IOS puede cancelar con animaciones UIViewPropertyAnimator !

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

Si pasa cierto que cancela la animación y se detiene justo donde se canceló. El método de ejecución no será llamado. Sin embargo, si pasa falsa usted es responsable de terminar la animación:

animator.finishAnimation(.start)

Puede terminar su animación y permanecer en el estado actual (.Current) o ir al estado inicial (.start) o al estado final (.end)

Por cierto, incluso se puede hacer una pausa y reiniciar más tarde ...

animator.pauseAnimation()
animator.startAnimation()

Nota: Si usted no quiere una abrupta cancelación se puede revertir la animación o cambiar su animación, incluso después de una pausa que

Si está animando una restricción cambiando la constante en lugar de una vista ninguna propiedad de los otros métodos funcionan en iOS 8.

Ejemplo 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:

Es necesario eliminar las animaciones de las capas de los puntos de vista de ser afectado por el cambio y la restricción de sus subcapas.

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

Si lo que desea es hacer una pausa / parada de la animación sin problemas

self.yourView.layer.speed = 0;

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

Ninguna de las anteriores resuelve para mí, pero esto ayudó: La animación UIView establece la propiedad de inmediato, entonces la anima. Se detiene la animación cuando la capa de presentación coincida con el modelo (el conjunto de propiedades).

He resuelto mi problema, que estaba "Quiero animar desde donde se mira como usted aparece" ( 'usted' significa la vista). Si quieres eso, entonces:

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

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

Yo uso un par de opciones, incluyendo UIViewAnimationOptionOverrideInheritedDuration

Pero debido a que la documentación de Apple es vaga, no sé si realmente prevalece sobre las otras animaciones cuando se utiliza, 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 eso 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 que cancelar alguna animación específica. La

+ (void)setAnimationsEnabled:(BOOL)enabled

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

1) hacer que su objeto animado una vista secundaria. Entonces, cuando se desea cancelar las animaciones para ese punto de vista, quitar la vista u ocultarlo. Muy simple, pero necesita volver a crear la subvista sin animaciones si es necesario para mantenerlo a la vista.

2) repetir el anim sólo uno, y hacer un selector delegado para reiniciar el anim, si es necesario, de esta manera:

-(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];
}
}

Problema con 2) es que siempre hay retardo de parada, el anim, ya que finaliza el ciclo de animación actual.

Espero que esto ayude.

Aunque cancele la animación en las formas anteriores didStopSelector animación todavía ejecuta. Así que si usted tiene estados lógicos en su aplicación impulsada por animaciones tendrá problemas. Por esta razón, con las formas descritas anteriormente Puedo utilizar la variable de contexto de animaciones UIView. Si pasa el estado actual de su programa por el contexto parámetro a la animación, cuando la animación se detiene la función didStopSelector puede decidir si se debe hacer algo o simplemente volver basado en el estado actual y el valor de estado pasa como contexto.

Swift versión 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()
CALayer * pLayer = self.layer.presentationLayer;
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView animateWithDuration:0.001 animations:^{
    self.frame = pLayer.frame;
}];

Para detener una animación sin volver a estado original o final:

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

Cuando trabajo con la animación UIStackView, además removeAllAnimations() tengo que configurar algunos valores iniciales a uno porque removeAllAnimations() puede ponerlos a estado impredecible. He stackView con view1 y view2 interior, y un punto de vista debería ser visible y uno oculto:

public func configureStackView(hideView1: Bool, hideView2: Bool) {
    let oldHideView1 = view1.isHidden
    let oldHideView2 = view2.isHidden
    view1.layer.removeAllAnimations()
    view2.layer.removeAllAnimations()
    view.layer.removeAllAnimations()
    stackView.layer.removeAllAnimations()
    // after stopping animation the values are unpredictable, so set values to old
    view1.isHidden = oldHideView1 //    <- Solution is here
    view2.isHidden = oldHideView2 //    <- Solution is here

    UIView.animate(withDuration: 0.3,
                   delay: 0.0,
                   usingSpringWithDamping: 0.9,
                   initialSpringVelocity: 1,
                   options: [],
                   animations: {
                    view1.isHidden = hideView1
                    view2.isHidden = hideView2
                    stackView.layoutIfNeeded()
    },
                   completion: nil)
}

Ninguna de las soluciones contestadas trabajado para mí. Me resuelto mis problemas de esta manera (no sé si se trata de una manera correcta?), Porque tenía problemas al llamar a esta demasiado rápido (cuando la animación anterior aún no había terminado). Paso mi animación deseada con customAnim bloque.

extension UIView
{

    func niceCustomTranstion(
        duration: CGFloat = 0.3,
        options: UIView.AnimationOptions = .transitionCrossDissolve,
        customAnim: @escaping () -> Void
        )
    {
        UIView.transition(
            with: self,
            duration: TimeInterval(duration),
            options: options,
            animations: {
                customAnim()
        },
            completion: { (finished) in
                if !finished
                {
                    // NOTE: This fixes possible flickering ON FAST TAPPINGS
                    // NOTE: This fixes possible flickering ON FAST TAPPINGS
                    // NOTE: This fixes possible flickering ON FAST TAPPINGS
                    self.layer.removeAllAnimations()
                    customAnim()
                }
        })

    }

}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top