I am using CABasicAnimation
to move and resize an image view. I want the image view to be added to the superview, animate, and then be removed from the superview.
In order to achieve that I am listening for delegate call of my CAAnimationGroup
, and as soon as it gets called I remove the image view from the superview.
The problem is that sometimes the image blinks in the initial location before being removed from the superview. What's the best way to avoid this behavior?
CAAnimationGroup *animGroup = [CAAnimationGroup animation]; animGroup.animations = [NSArray arrayWithObjects:moveAnim, scaleAnim, opacityAnim, nil]; animGroup.duration = .5; animGroup.delegate = self; [imageView.layer addAnimation:animGroup forKey:nil];
When you add an animation to a layer, the animation does not change the layer's properties. Instead, the system creates a copy of the layer. The original layer is called the model layer, and the duplicate is called the presentation layer. The presentation layer's properties change as the animation progresses, but the model layer's properties stay unchanged.
When you remove the animation, the system destroys the presentation layer, leaving only the model layer, and the model layer's properties then control how the layer is drawn. So if the model layer's properties don't match the final animated values of the presentation layer's properties, the layer will instantly reset to its appearance before the animation.
To fix this, you need to set the model layer's properties to the final values of the animation, and then add the animation to the layer. You want to do it in this order because changing a layer property can add an implicit animation for the property, which would conflict with the animation you want to explicitly add. You want to make sure your explicit animation overrides the implicit animation.
So how do you do all this? The basic recipe looks like this:
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"]; animation.fromValue = [NSValue valueWithCGPoint:myLayer.position]; layer.position = newPosition; // HERE I UPDATE THE MODEL LAYER'S PROPERTY animation.toValue = [NSValue valueWithCGPoint:myLayer.position]; animation.duration = .5; [myLayer addAnimation:animation forKey:animation.keyPath];
I haven't used an animation group so I don't know exactly what you might need to change. I just add each animation separately to the layer.
I also find it easier to use the +[CATransaction setCompletionBlock:]
method to set a completion handler for one or several animations, instead of trying to use an animation's delegate. You set the transaction's completion block, then add the animations:
[CATransaction begin]; { [CATransaction setCompletionBlock:^{ [self.imageView removeFromSuperview]; }]; [self addPositionAnimation]; [self addScaleAnimation]; [self addOpacityAnimation]; } [CATransaction commit];
CAAnimations are removed automatically when complete. There is a property removedOnCompletion
that controls this. You should set that to NO
.
Additionally, there is something known as the fillMode
which controls the animation's behavior before and after its duration. This is a property declared on CAMediaTiming
(which CAAnimation
conforms to). You should set this to kCAFillModeForwards
.
With both of these changes the animation should persist after it's complete. However, I don't know if you need to change these on the group, or on the individual animations within the group, or both.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With