I am trying to create a simple and animated pie chart using CAShapeLayer
. I want it to animate from 0 to a provided percentage.
To create the shape layer I use:
CGMutablePathRef piePath = CGPathCreateMutable();
CGPathMoveToPoint(piePath, NULL, self.frame.size.width/2, self.frame.size.height/2);
CGPathAddLineToPoint(piePath, NULL, self.frame.size.width/2, 0);
CGPathAddArc(piePath, NULL, self.frame.size.width/2, self.frame.size.height/2, radius, DEGREES_TO_RADIANS(-90), DEGREES_TO_RADIANS(-90), 0);
CGPathAddLineToPoint(piePath, NULL, self.frame.size.width/2 + radius * cos(DEGREES_TO_RADIANS(-90)), self.frame.size.height/2 + radius * sin(DEGREES_TO_RADIANS(-90)));
pie = [CAShapeLayer layer];
pie.fillColor = [UIColor redColor].CGColor;
pie.path = piePath;
[self.layer addSublayer:pie];
Then to animate I use:
CGMutablePathRef newPiePath = CGPathCreateMutable();
CGPathAddLineToPoint(newPiePath, NULL, self.frame.size.width/2, 0);
CGPathMoveToPoint(newPiePath, NULL, self.frame.size.width/2, self.frame.size.height/2);
CGPathAddArc(newPiePath, NULL, self.frame.size.width/2, self.frame.size.height/2, radius, DEGREES_TO_RADIANS(-90), DEGREES_TO_RADIANS(125), 0);
CGPathAddLineToPoint(newPiePath, NULL, self.frame.size.width/2 + radius * cos(DEGREES_TO_RADIANS(125)), self.frame.size.height/2 + radius * sin(DEGREES_TO_RADIANS(125)));
CABasicAnimation *pieAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
pieAnimation.duration = 1.0;
pieAnimation.removedOnCompletion = NO;
pieAnimation.fillMode = kCAFillModeForwards;
pieAnimation.fromValue = pie.path;
pieAnimation.toValue = newPiePath;
[pie addAnimation:pieAnimation forKey:@"animatePath"];
Obviously, this is animating in a really odd way. The shape just kind of grows into its final state. Is there an easy way to make this animation follow the direction of the circle? Or is that a limitation of CAShapeLayer
animations?
Quick copy/paste Swift translation of this excellent Objective-C answer.
In Swift 3
I know this question has long been answered, but I don't quite think this is a good case for
CAShapeLayer
andCAKeyframeAnimation
. Core Animation has the power to do animation tweening for us. Here's a class (with a wrappingUIView
, if you like) that I use to accomplish the effect pretty well.The layer subclass enables implicit animation for the progress property, but the view class wraps its setter in a
UIView
animation method. The interesting (and ultimately useful) side effect of using a 0.0 length animation withUIViewAnimationOptionBeginFromCurrentState
is that each animation cancels out the previous one, leading to a smooth, fast, high-framerate pie, like this (animated) and this (not animated, but incremented).DZRoundProgressView.h
DZRoundProgressView.m
I suggest you make a keyframe animation instead:
Basic animation is good for scalars/vectors. But do you want it to interpolate your paths?