Animated Pie Chart in iOS

I am trying to create an animated pie chart in iOS, which acts basically like this:

Pie chart progression

In a nutshell, it starts as a gray circle, and as the animation progresses, the arrow moves in a circle until it reaches the percentage I specified.

I used the sample code that Zachary Waldowski published in this SO question:

Animated CAShapeLayer Pie

This led me to create basic animations. A vintage piece of cake is growing to hit the right size. What I'm struggling with is comparing the arrow with the animation so that it drags on when a piece of cake grows.

Any thoughts on how I can do this?

+4
source share
2 answers

Ok, I found a solution.

Based on the work Zachary Waldowski created (see my original post), I was able to do everything in CALayer.

In a nutshell, I draw one outer circle in the dark, the smaller circle is light gray, the stroked path in white, then draw a triangle for the arrowhead manually.

Here is the relevant section of the code that does the magic:

- (void)drawInContext:(CGContextRef)context {
    CGRect circleRect = CGRectInset(self.bounds, 1, 1);
    CGFloat startAngle = -M_PI / 2;
    CGFloat endAngle = self.progress * 2 * M_PI + startAngle;

    CGColorRef outerPieColor = [[UIColor colorWithRed: 137.0 / 255.0 green: 12.0 / 255.0 blue: 88.0 / 255.0 alpha: 1.0] CGColor];
    CGColorRef innerPieColor = [[UIColor colorWithRed: 235.0 / 255.0 green: 214.0 / 255.0 blue: 227.0 / 255.0 alpha: 1.0] CGColor];
    CGColorRef arrowColor = [[UIColor whiteColor] CGColor];

    // Draw outer pie
    CGFloat outerRadius = CGRectGetMidX(circleRect);
    CGPoint center = CGPointMake(CGRectGetMidX(circleRect), CGRectGetMidY(circleRect));

    CGContextSetFillColorWithColor(context, outerPieColor);
    CGContextMoveToPoint(context, center.x, center.y);
    CGContextAddArc(context, center.x, center.y, outerRadius, startAngle, endAngle, 0);
    CGContextClosePath(context);
    CGContextFillPath(context);

    // Draw inner pie
    CGFloat innerRadius = CGRectGetMidX(circleRect) * 0.45;

    CGContextSetFillColorWithColor(context, innerPieColor);
    CGContextMoveToPoint(context, center.x, center.y);
    CGContextAddArc(context, center.x, center.y, innerRadius, startAngle, endAngle, 0);
    CGContextClosePath(context);
    CGContextFillPath(context);

    // Draw the White Line
    CGFloat lineRadius = CGRectGetMidX(circleRect) * 0.72;
    CGFloat arrowWidth = 0.35;

    CGContextSetStrokeColorWithColor(context, arrowColor);
    CGContextSetFillColorWithColor(context, arrowColor);

    CGMutablePathRef path = CGPathCreateMutable();
    CGContextSetLineWidth(context, 16);
    CGFloat lineEndAngle = ((endAngle - startAngle) >= arrowWidth) ? endAngle - arrowWidth : endAngle;
    CGPathAddArc(path, NULL, center.x, center.y, lineRadius, startAngle, lineEndAngle, 0);
    CGContextAddPath(context, path);
    CGContextStrokePath(context);

    // Draw the Triangle pointer
    CGFloat arrowStartAngle = lineEndAngle - 0.01;
    CGFloat arrowOuterRadius = CGRectGetMidX(circleRect) * 0.90;
    CGFloat arrowInnerRadius = CGRectGetMidX(circleRect) * 0.54;

    CGFloat arrowX = center.x + (arrowOuterRadius * cosf(arrowStartAngle));
    CGFloat arrowY = center.y + (arrowOuterRadius * sinf(arrowStartAngle));

    CGContextMoveToPoint   (context, arrowX, arrowY);  // top corner

    arrowX = center.x + (arrowInnerRadius * cosf(arrowStartAngle));
    arrowY = center.y + (arrowInnerRadius * sinf(arrowStartAngle));

    CGContextAddLineToPoint(context, arrowX, arrowY);  // bottom corner

    arrowX = center.x + (lineRadius * cosf(endAngle));
    arrowY = center.y + (lineRadius * sinf(endAngle));

    CGContextAddLineToPoint(context, arrowX, arrowY);  // point
    CGContextClosePath(context);
    CGContextFillPath(context);

    [super drawInContext: context];
}
+4
source

Ask for the arrow pie as the image.

At each step, draw this image by turning it a little. Draw a gray picture on the image, choosing the correct image rotation angles.

+2
source

All Articles