ios - animate - ¿Cancelar una animación UIView?
ui animation swift 3 (15)
¿Es posible cancelar una animación UIView
mientras está en curso? ¿O tendría que caer al nivel de 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 se complete la animación y termine el evento de animación final, quiero cancelarlo (en pocas palabras). es posible? Buscar en Internet encuentra a algunas personas que hacen la misma pregunta sin respuestas, y una o dos personas especulan que no se puede hacer.
En iOS 4 y superior, use la opción UIViewAnimationOptionBeginFromCurrentState
en la segunda animación para cortar la primera animación.
Como ejemplo, suponga que tiene una vista con un indicador de actividad. Desea atenuar el indicador de actividad mientras comienza alguna actividad que puede consumir mucho tiempo y desaparecer cuando finaliza la actividad. En el código a continuación, 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;
}
}];
}
Incluso si cancela la animación en las formas anteriores, la animación didStopSelector
aún se ejecuta. Entonces, si tiene estados lógicos en su aplicación controlados por animaciones, tendrá problemas. Por esta razón, con las formas descritas anteriormente, uso la variable de contexto de UIView
animaciones UIView
. Si pasa el estado actual de su programa por el parámetro de contexto a la animación, cuando la animación se detenga, su función didStopSelector
puede decidir si debería hacer algo o simplemente regresar según el estado actual y el valor del estado pasado como contexto.
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 usar el método +setAnimationBeginsFromCurrentState:
para comenzar desde el estado actual. Cuando lo configura en SÍ, la animación actual se corta. Parece 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];
La forma más sencilla de detener todas las animaciones en una vista particular, inmediatamente , es esta:
Enlace el proyecto a QuartzCore.framework. Al comienzo de su código:
#import <QuartzCore/QuartzCore.h>
Ahora, cuando quieras detener todas las animaciones en una vista muerta en sus pistas, di esto:
[CATransaction begin];
[theView.layer removeAllAnimations];
[CATransaction commit];
La línea media funcionaría por sí sola, pero hay un retraso hasta que finalice el runloop (el "momento de redibujado"). Para evitar ese retraso, ajuste el comando en un bloque de transacción explícito como se muestra. Este trabajo siempre que no se hayan realizado otros cambios en esta capa en el runloop actual.
Lamento resucitar esta respuesta, pero en iOS 10 las cosas cambiaron un poco, ¡y ahora es posible cancelar e incluso puede 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 verdadero, cancela la animación y se detiene justo donde la canceló. El método de finalización no será llamado. Sin embargo, si pasas falso eres responsable de terminar la animación:
animator.finishAnimation(.start)
Puede finalizar su animación y permanecer en el estado actual (.current) 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 revertir su animación o incluso cambiarla después de pausarla!
Nada de lo anterior lo resolvió por mí, pero esto ayudó: La animación 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 establecida).
Resolví mi problema, que era "Quiero animar desde donde pareces que apareces" ("tú" significa la vista). Si quieres ESO, entonces:
- Añadir QuartzCore.
-
CALayer * pLayer = theView.layer.presentationLayer;
establecer la posición a la capa de presentación
Uso algunas opciones incluyendo UIViewAnimationOptionOverrideInheritedDuration
Pero debido a que la documentación de Apple es vaga, no sé si realmente reemplaza las otras animaciones cuando se usan, o simplemente reinicia 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.
Para cancelar una animación, simplemente debe configurar la propiedad que se está animando actualmente, fuera de la animación UIView. Eso detendrá la animación donde sea que esté, y UIView saltará a la configuración que acabas de definir.
Para pausar una animación sin volver al estado original o final:
CFTimeInterval paused_time = [myView.layer convertTime:CACurrentMediaTime() fromLayer:nil];
myView.layer.speed = 0.0;
myView.layer.timeOffset = paused_time;
Si está animando una restricción cambiando 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 las vistas 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 suavemente
self.yourView.layer.speed = 0;
Tengo el mismo problema; Las API no tienen nada para cancelar alguna animación específica. los
+ (void)setAnimationsEnabled:(BOOL)enabled
desactiva TODAS las animaciones, y por lo tanto no funciona para mí. Hay dos soluciones:
1) Haz de tu objeto animado 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) repita la animación solo una, y haga un selector de delegado para reiniciar la animación si es necesario, como esto:
-(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 una demora en detener la animación cuando termina el ciclo de animación actual.
Espero que esto ayude.
Utilizar:
#import <QuartzCore/QuartzCore.h>
.......
[myView.layer removeAllAnimations];
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()
CALayer * pLayer = self.layer.presentationLayer;
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView animateWithDuration:0.001 animations:^{
self.frame = pLayer.frame;
}];
[UIView setAnimationsEnabled:NO];
// your code here
[UIView setAnimationsEnabled:YES];