I am trying to animate the drawing of a UIBeizerPath (in my example a triangle) in a UIView subclass. However, the entire subview is animating instead of the shape.
Is there something I am missing with the animation?
- (void)drawRect:(CGRect)rect {
CAShapeLayer *drawLayer = [CAShapeLayer layer];
drawLayer.frame = CGRectMake(0, 0, 100, 100);
drawLayer.strokeColor = [UIColor greenColor].CGColor;
drawLayer.lineWidth = 4.0;
[self.layer addSublayer:drawLayer];
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0,0)];
[path addLineToPoint:CGPointMake(50,100)];
[path addLineToPoint:CGPointMake(100,0)];
[path closePath];
CGPoint center = [self convertPoint:self.center fromView:nil];
[path applyTransform:CGAffineTransformMakeTranslation(center.x, center.y)];
[[UIColor redColor] set];
[path fill];
[[UIColor blueColor] setStroke];
path.lineWidth = 3.0f;
[path stroke];
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
pathAnimation.duration = 4.0f;
pathAnimation.path = path.CGPath;
pathAnimation.calculationMode = kCAAnimationLinear;
[drawLayer addAnimation:pathAnimation forKey:@"position"];
}
You are creating a
CAShapeLayer
, but then not doing anything useful with it. Let's fix that.Don't set up layers and animations in
-drawRect:
, because that's strictly meant as a time to do drawing using the CoreGraphics or UIKit APIs. Instead, you want the CAShapeLayer to draw the triangle -- that way you can animate it.CAKeyframeAnimation.path is meant for something completely different (e.g. moving a layer along a path).
Your animation is animating the
position
value of the layer. No surprise that it moves the layer! You want to animate thepath
value instead.The idea behind CAKeyframeAnimation is that you provide it an array of
values
to set the layer's property to. During the time between keyframes, it will interpolate between the two adjacent keyframes. So you need to give it several paths -- one for each side.Interpolating arbitrary paths is difficult. CA's path interpolation works best when the paths have the same same number and kind of elements. So, we make sure all our paths have the same structure, just with some points on top of each other.
The secret to animation, and maybe to computers in general: you must be precise in explaining what you want to happen. "I want to animate the drawing of each point, so it appears to be animated" is not nearly enough information.
Here's a UIView subclass that I think does what you're asking for, or at least close. To animate, hook a button up to the
-animate:
action.SPAnimatedShapeView.h:
SPAnimatedShapeView.m: