Animating Calayer's Shadowpath Property

Animating CALayer's shadowPath property

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.

Animating a CALayer shadowpath

At first, small square with drop shadow.

ss

When button pushed, square and shadow grow bigger together.

ss

The main code is below:

[CATransaction begin];
[CATransaction setAnimationDuration:5.0];
CAMediaTimingFunction *timing = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
[CATransaction setAnimationTimingFunction:timing];
layer.frame = CGRectMake(0,0,100,100);
[CATransaction commit];

CABasicAnimation *shadowAnimation = [CABasicAnimation animationWithKeyPath:@"shadowPath"];
shadowAnimation.duration = 5.0;
shadowAnimation.fromValue = (id)[UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 50, 50)].CGPath;
shadowAnimation.toValue = (id)[UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 100, 100)].CGPath;
[layer addAnimation:shadowAnimation forKey:@"shadow"];

You can download this project from GitHub and just run it.

https://github.com/weed/p120812_CALayerShadowTest

This question was very hard for me ! :)

How to disable user interaction during animating CALayer's shadowPath property

If you want to stop any user interaction(actually you will stop everything) call your problem method with blocking main thread selector:

    [self performSelectorOnMainThread:@selector(blockingMethod:) withObject:blockingMethodParam waitUntilDone:YES]

This way you make sure everything stops until blockingMethod is fully executed. However you concept approach is not very good as no user ever wants it's UI to be blocked especially when there is no some kind of waiting screen.

reference:

– performSelectorOnMainThread:withObject:waitUntilDone:

Regards,

hris.to

UIView Animation, Transforming layer.shadowPath

The UIView animations don’t always allow you to animate CALayer attributes; try using a CABasicAnimation instead.

CAShapeLayer shadowPath animation. How to prevent shadow fill on animation completion?

I was able to solve the issue, with the help of this answer, by creating a CALayer for the shadow and adding the CAShapeLayer as a sublayer:

    let path = createBezierPath() // Get a path
let color = randomCGColor() // Color of path and shadow
let lineWidth = CGFloat(arc4random_uniform(50) + 11) // Width of line and shadow radius

// Shape layer properties
shapeLayer.path = path.CGPath
shapeLayer.lineJoin = kCALineJoinRound
shapeLayer.lineCap = kCALineCapRound
shapeLayer.strokeColor = color
shapeLayer.lineWidth = lineWidth
shapeLayer.fillColor = UIColor.clearColor().CGColor

// Create shadow layer
let shadowLayer = CALayer()
shadowLayer.frame = self.bounds
shadowLayer.shadowColor = color
shadowLayer.shadowOffset = CGSizeZero
shadowLayer.shadowRadius = lineWidth
shadowLayer.shadowOpacity = 1.0
shadowLayer.backgroundColor = UIColor.clearColor().CGColor
shadowLayer.insertSublayer(shapeLayer, atIndex: 0)

// Add shadow layer
self.layer.addSublayer(shadowLayer)

// Stroke path animation
let pathAnimation: CABasicAnimation = CABasicAnimation(keyPath: "strokeEnd")
pathAnimation.fromValue = 0.0
pathAnimation.toValue = 1.0
pathAnimation.duration = 5.0
shapeLayer.addAnimation(pathAnimation, forKey: "strokeAnimation")

// Shadow path animation
let shadowPathAnimation: CABasicAnimation = CABasicAnimation(keyPath: "shadowPath")
shadowPathAnimation.fromValue = 0.0
shadowPathAnimation.toValue = path.CGPath
shadowLayer.addAnimation(shadowPathAnimation, forKey: "shadowAnimation")

Example of the result:

Sample Image

CABasicAnimation with CALayer path doesn't animate

It looks to me like you are creating a shape layer that does not have a path, then trying to animate adding a path to it. Shape layers are special case, and don't work that way.

You have to have a path in the shape layer before and after the animation, and the path needs to have the same number of points in it both before and after.

You would need to create a rounded rectangle path with a corner radius of 0 (manually, using a series of sides and corner arcs), and then build a new path with non zero radii for the corners you want to round and install that path as your animation.

Even that might not work, though, because the path needs to have exactly the same number of points in it, and I suspect that the arcs would simplify to points when the radius is zero.

I just found a UIBezierPath call that will create a rectangle where you can select which corners to round. The call is bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:

That will create a rectangle with as many rounded corners as you like. However, I'm not sure if it will work for path animation. You might need to request all corners be rounded with the 2 non-rounded corners set to zero radius. That way you MIGHT get a path with the same number of points in it as a rounded rectangle path so the path animation works correctly. You'll have to try it.



Related Topics



Leave a reply



Submit