I am rotating a CALayer and trying to stop it at its final position after animation is completed.
But after animation completes it resets to its initial position.
It seems that removedOnCompletion flag set to false and fillMode set to kCAFillModeForwards doesn't work for me either.
After I apply new animation on a layer, an animating object resets to its initial state and then animates from that state. What has to be done additionally is to set the model layer's desired property according to its presentation layer's property before setting new animation like so:
someLayer.path = ((CAShapeLayer *)[someLayer presentationLayer]).path;
[someLayer addAnimation:someAnimation forKey:@"someAnimation"];
This works:
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")
Core animation shows a 'presentation layer' atop your normal layer during the animation. So set the opacity (or whatever) to what you want to be seen when the animation finishes and the presentation layer goes away. Do this on the line before you add the animation to avoid a flicker when it completes.
If you want to have a delay, do the following:
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")
Finally, if you use 'removedOnCompletion = false' it'll leak CAAnimations until the layer is eventually disposed - avoid.
The easiest solution is to use implicit animations. This will handle all of that trouble for you:
self.layer?.backgroundColor = NSColor.red.cgColor;
If you want to customize e.g. the duration, you can use NSAnimationContext
:
NSAnimationContext.beginGrouping();
NSAnimationContext.current.duration = 0.5;
self.layer?.backgroundColor = NSColor.red.cgColor;
NSAnimationContext.endGrouping();
Note: This is only tested on macOS.
I initially did not see any animation when doing this. The problem is that the layer of a view-backed layer does not implicit animate. To solve this, make sure you add a layer yourself (before setting the view to layer-backed).
An example how to do this would be:
override func awakeFromNib() {
self.layer = CALayer();
//self.wantsLayer = true;
}
Using self.wantsLayer
did not make any difference in my testing, but it could have some side effects that I do not know of.