iphone - CABasicAnimation se restablece al valor inicial una vez completada la animación
(12)
Así que mi problema era que estaba tratando de rotar un objeto en el gesto panorámico, por lo que tenía múltiples animaciones idénticas en cada movimiento. Tenía tanto fillMode = kCAFillModeForwards
como isRemovedOnCompletion = false
pero no sirvió de nada. En mi caso, tuve que asegurarme de que la clave de animación sea diferente cada vez que agrego una nueva animación :
let angle = // here is my computed angle
let rotate = CABasicAnimation(keyPath: "transform.rotation.z")
rotate.toValue = angle
rotate.duration = 0.1
rotate.isRemovedOnCompletion = false
rotate.fillMode = kCAFillModeForwards
head.layer.add(rotate, forKey: "rotate/(angle)")
Estoy rotando un CALayer e intentando detenerlo en su posición final una vez completada la animación.
Pero después de que la animación se complete, se restablece a su posición inicial.
(Los documentos xcode dicen explícitamente que la animación no actualizará el valor de la propiedad).
cualquier sugerencia de cómo lograr esto.
El problema con removedOnCompletion es que el elemento UI no permite la interacción del usuario.
La técnica consiste en establecer el valor FROM en la animación y el valor TO en el objeto. La animación llenará automáticamente el valor TO antes de que comience, y cuando se elimine, dejará el objeto en su estado correcto.
// fade in
CABasicAnimation *alphaAnimation = [CABasicAnimation animationWithKeyPath: @"opacity"];
alphaAnimation.fillMode = kCAFillModeForwards;
alphaAnimation.fromValue = NUM_FLOAT(0);
self.view.layer.opacity = 1;
[self.view.layer addAnimation: alphaAnimation forKey: @"fade"];
Establezca la siguiente propiedad:
animationObject.removedOnCompletion = NO;
Esto funciona:
let animation = CABasicAnimation(keyPath: "opacity")
animation.fromValue = 0
animation.toValue = 1
animation.duration = 0.3
someLayer.opacity = 1 // important, this is the state you want visible after the animation finishes.
someLayer.addAnimation(animation, forKey: "myAnimation")
La animación principal muestra una "capa de presentación" encima de la capa normal durante la animación. Por lo tanto, establezca la opacidad (o lo que sea) en lo que desea que se vea cuando la animación finalice y la capa de presentación desaparezca. Haga esto en la línea antes de agregar la animación para evitar un parpadeo cuando se complete.
Si quieres tener un retraso, haz lo siguiente:
let animation = CABasicAnimation(keyPath: "opacity")
animation.fromValue = 0
animation.toValue = 1
animation.duration = 0.3
animation.beginTime = someLayer.convertTime(CACurrentMediaTime(), fromLayer: nil) + 1
animation.fillMode = kCAFillModeBackwards // So the opacity is 0 while the animation waits to start.
someLayer.opacity = 1 // <- important, this is the state you want visible after the animation finishes.
someLayer.addAnimation(animation, forKey: "myAnimation")
Finalmente, si usa ''removedOnCompletion = false'', se filtrarán CAAnimations hasta que la capa se elimine definitivamente, evite.
La respuesta de @Leslie Godwin no es realmente buena, "self.view.layer.opacity = 1;" se realiza de inmediato (tarda aproximadamente un segundo), por favor, fije alphaAnimation.duration a 10.0, si tiene dudas. Tienes que eliminar esta línea.
Entonces, cuando arreglas fillMode a kCAFillModeForwards y removeOnCompletion a NO, dejas que la animación permanezca en la capa. Si arreglas el delegado de animación e intentas algo como:
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
[theLayer removeAllAnimations];
}
... la capa se restaura inmediatamente en el momento de ejecutar esta línea. Es lo que queríamos evitar.
Debe corregir la propiedad de capa antes de eliminar la animación de ella. Prueba esto:
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
if([anim isKindOfClass:[CABasicAnimation class] ]) // check, because of the cast
{
CALayer *theLayer = 0;
if(anim==[_b1 animationForKey:@"opacity"])
theLayer = _b1; // I have two layers
else
if(anim==[_b2 animationForKey:@"opacity"])
theLayer = _b2;
if(theLayer)
{
CGFloat toValue = [((CABasicAnimation*)anim).toValue floatValue];
[theLayer setOpacity:toValue];
[theLayer removeAllAnimations];
}
}
}
Parece que el indicador removedOnCompletion establecido en false y fillMode establecido en kCAFillModeForwards tampoco me funciona.
Después de aplicar nueva animación en una capa, un objeto animado se restablece a su estado inicial y luego se anima desde ese estado. Lo que se debe hacer adicionalmente es establecer la propiedad deseada de la capa de modelo de acuerdo con la propiedad de la capa de presentación antes de establecer una nueva animación como esta:
someLayer.path = ((CAShapeLayer *)[someLayer presentationLayer]).path;
[someLayer addAnimation:someAnimation forKey:@"someAnimation"];
Simplemente configurar fillMode
y removedOnCompletion
no funcionó para mí. Resolví el problema estableciendo todas las propiedades siguientes en el objeto CABasicAnimation:
CABasicAnimation* ba = [CABasicAnimation animationWithKeyPath:@"transform"];
ba.duration = 0.38f;
ba.fillMode = kCAFillModeForwards;
ba.removedOnCompletion = NO;
ba.autoreverses = NO;
ba.repeatCount = 0;
ba.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.85f, 0.85f, 1.0f)];
[myView.layer addAnimation:ba forKey:nil];
Este código transforma myView
en el 85% de su tamaño (la 3ª dimensión sin modificaciones).
Simplemente puede establecer la clave de CABasicAnimation
en la position
cuando la agrega a la capa. Al hacer esto, anulará la animación implícita realizada en la posición del pase actual en el ciclo de ejecución.
CGFloat yOffset = 30;
CGPoint endPosition = CGPointMake(someLayer.position.x,someLayer.position.y + yOffset);
someLayer.position = endPosition; // Implicit animation for position
CABasicAnimation * animation =[CABasicAnimation animationWithKeyPath:@"position.y"];
animation.fromValue = @(someLayer.position.y);
animation.toValue = @(someLayer.position.y + yOffset);
[someLayer addAnimation:animation forKey:@"position"]; // The explicit animation ''animation'' override implicit animation
Puede obtener más información sobre 2011 Apple WWDC Video Session 421 - Core Animation Essentials (en el medio del video)
Sin usar el removedOnCompletion
Puedes probar esta técnica:
self.animateOnX(item: shapeLayer)
func animateOnX(item:CAShapeLayer)
{
let endPostion = CGPoint(x: 200, y: 0)
let pathAnimation = CABasicAnimation(keyPath: "position")
//
pathAnimation.duration = 20
pathAnimation.fromValue = CGPoint(x: 0, y: 0)//comment this line and notice the difference
pathAnimation.toValue = endPostion
pathAnimation.fillMode = kCAFillModeBoth
item.position = endPostion//prevent the CABasicAnimation from resetting item''s position when the animation finishes
item.add(pathAnimation, forKey: nil)
}
Un CALayer tiene una capa de modelo y una capa de presentación. Durante una animación, la capa de presentación se actualiza independientemente del modelo. Cuando se completa la animación, la capa de presentación se actualiza con el valor del modelo. Si desea evitar un salto discordante después de que finaliza la animación, la clave es mantener las dos capas sincronizadas.
Si conoce el valor final, puede simplemente configurar el modelo directamente.
self.view.layer.opacity = 1;
Pero si tiene una animación en la que no conoce la posición final (por ejemplo, un desvanecimiento lento que el usuario puede pausar y luego invertir), puede consultar la capa de presentación directamente para encontrar el valor actual y luego actualizar el modelo.
NSNumber *opacity = [self.layer.presentationLayer valueForKeyPath:@"opacity"];
[self.layer setValue:opacity forKeyPath:@"opacity"];
Extraer el valor de la capa de presentación también es particularmente útil para escalar o girar las trayectorias clave. (por ejemplo, transform.rotation
, transform.rotation
)
solo ponlo dentro de tu código
CAAnimationGroup *theGroup = [CAAnimationGroup animation];
theGroup.fillMode = kCAFillModeForwards;
theGroup.removedOnCompletion = NO;
Editar : Aquí está la respuesta, es una combinación de mi respuesta y la de Krishnan.
cabasicanimation.fillMode = kCAFillModeForwards;
cabasicanimation.removedOnCompletion = NO;
El valor predeterminado es kCAFillModeRemoved
. (¿Cuál es el comportamiento de reinicio que estás viendo?)