programming, user experience, and more


Implicit Animation for CAShapeLayer's Path

I was recently working on a project that required some custom drawing that also needed to be animated while resizing. I started out using Core Graphics in -drawRect of my custom view but when it came around to animating the drawing it was not possible.

I decided to try out using a CAShapeLayer that allows you to set a path, line color, fill color and more. This worked beautifully for drawing but caused headaches at first as examples online all manually animated the path property of CAShapeLayer with a CABasicAnimation. My problem was that the view in question was within a table view cell and I was not explicitly resizing it so I couldn't find an elegant way to add my custom animation.

Then I found a method on CALayer called -actionForKey. This is called each time a property is changed to determine what action should be taken. You can return an animation for whatever property you desire. In my case I wanted to implicitly animate the path property so I implemented my own subclass of CAShapeLayer and implemented -actionForKey in the following way:

- (id)actionForKey:(NSString *)event {
    if ([event isEqualToString:@"path"]) {
        CABasicAnimation *animation = [CABasicAnimation
            animationWithKeyPath:event];
        animation.duration = [CATransaction animationDuration];
        animation.timingFunction = [CATransaction
            animationTimingFunction];
        return animation;
    }
    return [super actionForKey:event];
}

Basically this method creates a basic animation which automatically uses the before and after value. The only things I have to set are the duration and timingFunction. I use the defaults in CATransaction so that I can override them from an external class if necessary with +setAnimationDuration: and +setAnimationTimingFunction:.

Now any time the path is changed on the layer it will automatically animate it. I can reset the path in my -layoutSubviews and not worry about the rest.