I am aware that a CALayer's shadowPath is only animatable using explicit animations, however I still cannot get this to work. I suspect that I am not passing the toValue
properly - as I understand this has to be an id
, yet the property takes a CGPathRef. Storing this in a UIBezierPath
does not seem to work. I am using the following code to test:
CABasicAnimation *theAnimation = [CABasicAnimation animationWithKeyPath:@"shadowPath"];
theAnimation.duration = 3.0;
theAnimation.toValue = [UIBezierPath bezierPathWithRect:CGRectMake(-10.0, -10.0, 50.0, 50.0)];
[self.view.layer addAnimation:theAnimation forKey:@"animateShadowPath"];
(I am using minus values so as to ensure the shadow extends beyond a view that lies on top of it... the layer's masksToBounds
property is set to NO
).
How is animation of the shadowPath achieved?
UPDATE
Problem nearly solved. Unfortunately, the main problem was a somewhat careless error...
The mistake I made was to add the animation to the root layer of the view controller, rather than the layer I had dedicated to the shadow. Also, @pe8ter was correct in that the toValue
needs to be a CGPathRef
cast to id
(obviously when I had tried this before I still had no animation due to the wrong layer mistake). The animation works with the following code:
CABasicAnimation *theAnimation = [CABasicAnimation animationWithKeyPath:@"shadowPath"];
theAnimation.duration = 3.0;
theAnimation.toValue = (id)[UIBezierPath bezierPathWithRect:myRect].CGPath;
[controller.shadowLayer addAnimation:theAnimation forKey:@"shadowPath"];
I appreciate this was difficult to spot from the sample code I provided. Hopefully it can still be of use to people in a similar situation though.
However, when I try and add the line
controller.shadowLayer.shadowPath = [UIBezierPath bezierPathWithRect:myRect].CGPath;
the animation stops working, and the shadow just jumps to the final position instantly. Docs say to add the animation with the same key as the property being changed so as to override the implicit animation created when setting the value of the property, however shadowPath can't generate implicit animations... so how do I get the new property to stay after the animation?
shadowPath controls the shape of the shadow. This defaults to nil , which causes UIKit to render the view offscreen to figure out the shadow shape. shadowRadius controls how blurred the shadow is. This defaults to 3 points.
shadowOpacity : the opacity of the layer's shadow. The value of this property must be in the range 0.0 (invisible) to 1.0 (opaque). The default value of this property is 0.0 .
Firstly, you did not set the animation's fromValue
.
Secondly, you're correct: toValue
accepts a CGPathRef
, except it needs to be cast to id
. Do something like this:
theAnimation.toValue = (id)[UIBezierPath bezierPathWithRect:newRect].CGPath;
You'll also need to set the shadowPath
property of the layer explicitly if you want the change to remain after animation.
let cornerRadious = 10.0
//
let shadowPathFrom = UIBezierPath(roundedRect: rect1, cornerRadius: cornerRadious)
let shadowPathTo = UIBezierPath(roundedRect: rect2, cornerRadius: cornerRadious)
//
layer.masksToBounds = false
layer.shadowColor = UIColor.yellowColor().CGColor
layer.shadowOpacity = 0.6
//
let shadowAnimation = CABasicAnimation(keyPath: "shadowPath")
shadowAnimation.fromValue = shadowPathFrom.CGPath
shadowAnimation.toValue = shadowPathTo.CGPath
shadowAnimation.duration = 0.4
shadowAnimation.autoreverses = true
shadowAnimation.removedOnCompletion = true
shadowAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
layer.addAnimation(shadowAnimation, forKey: "shadowAnimation")
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