4

I'm trying to animate the scale then the opacity of a CALayer, like so:

CABasicAnimation *scaleUp = [CABasicAnimation animationWithKeyPath:@"transform"];
scaleUp.fromValue = [NSValue valueWithCATransform3D:self.timerProgressLayer.transform];
scaleUp.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0, 1.0, 1.0)];
scaleUp.duration = 0.25;
scaleUp.fillMode = kCAFillModeForwards;

CABasicAnimation *fadeOut = [CABasicAnimation animationWithKeyPath:@"opacity"];
fadeOut.fromValue = @(1.0);
fadeOut.toValue = @(0.0);
fadeOut.beginTime = 0.3;
fadeOut.duration = 0.25;
fadeOut.fillMode = kCAFillModeForwards;

CAAnimationGroup *group = [CAAnimationGroup animation];
group.animations = @[scaleUp, fadeOut];
group.removedOnCompletion = YES;
group.duration = fadeOut.beginTime + fadeOut.duration;

[self.timerProgressLayer addAnimation:group forKey:@"trigger"];

That's simple enough, and the animation itself works fine. However, at the end of the animation it's removed and the values revert to the ones at the beginning. To combat this, I set the properties manually, immediately after the addAnimation: call:

self.timerProgressLayer.opacity = 0.0;
self.timerProgressLayer.transform = CATransform3DMakeScale(1.0, 1.0, 1.0);

However, these calls override my animation, and the layer fades out and scales immediately. If I use the animation's delegate or [CATransaction setCompletionBlock:] to set the properties at the end of the animation, a lot of the time (but not 100% of the time), a single frame of the old state gets through between the end of the animation and the properties being set.

How can I use CAAnimationGroup to animate some properties, removing the animation at the end without the old values peeking through for a frame?

iKenndac
  • 18,730
  • 3
  • 35
  • 51

1 Answers1

3

I've given the long version of this answer previously. There is no reason to repeat the detailed explanation here.

But the short answer is that you are seeing the layer's implicit animations being applied on top of the explicit animation. I have previously written a detailed explanation about implicit and explicit animations and multiple simulations animation, if you want to read more about it.


As described in "the long answer". The solution to your problem is to update the properties, but to temporarily disable the implicit animations so that they aren't applied on top of your explicit animations:

[CATransaction begin];
[CATransaction setDisableActions:YES]; // actions are disabled for now

self.timerProgressLayer.opacity = 0.0;
self.timerProgressLayer.transform = CATransform3DMakeScale(1.0, 1.0, 1.0);

[CATransaction commit];                // until here
Community
  • 1
  • 1
David Rönnqvist
  • 56,267
  • 18
  • 167
  • 205
  • Oops, that was one of the things I tried — doing that completely stomps over the animations, visually setting the properties immediately. – iKenndac Apr 01 '15 at 11:28
  • You should probably have a backward or both fill mode so that the "old" animation value is displayed while waiting for the begin time to pass. – David Rönnqvist Apr 01 '15 at 11:31
  • Ah! Fixing the fill mode fixed the problem. Thank you! – iKenndac Apr 01 '15 at 11:39