Search code examples
iosobjective-cuibezierpathcashapelayercabasicanimation

CABasicAnimation reverse from current position (like progress bar animation)


I am using a circle (UIBezierPath) in my app as a mini progress bar. One problem I have is that I am only able to animate the circle once in one direction only. Let say I have the circle drawn to 80% and I want to shrink it down to 60%, the whole circle is re-drawn which is not what I want.

When using a progress bar, if you reduce the current displayed percentage, the entire bar is not redrawn, the bar simply shrinks down in size from it's current position to the new percentage, that is what I want with my circle layer.

Here is my circle initial setup code:

CAShapeLayer *greenPlayButtonCircle;

greenPlayButtonCircle = [CAShapeLayer layer];
[greenPlayButtonCircle setPath:[UIBezierPath bezierPathWithArcCenter:CGPointMake(boxView.bounds.origin.x, boxView.bounds.origin.y) radius:(boxView.frame.size.width / 2) startAngle:DEGREES_TO_RADIANS(-90) endAngle:DEGREES_TO_RADIANS(270) clockwise:YES].CGPath];
[greenPlayButtonCircle setFillColor:[UIColor clearColor].CGColor];
[greenPlayButtonCircle setStrokeColor:[UIColor greenColor].CGColor];
[greenPlayButtonCircle setLineWidth:6.0];
[greenPlayButtonCircle setPosition:boxView.center];
[greenPlayButtonCircle setAnchorPoint:CGPointMake(0.5, 0.5)];
    
[self.view.layer addSublayer:greenPlayButtonCircle];

And here is the code I am using to try to reduce the circle percentage (drawn section):

[greenPlayButtonCircle setPath:[UIBezierPath bezierPathWithArcCenter:CGPointMake(boxView.bounds.origin.x, boxView.bounds.origin.y) radius:(boxView.frame.size.width / 2) startAngle:DEGREES_TO_RADIANS(-90) endAngle:DEGREES_TO_RADIANS(270) clockwise:YES].CGPath];
    
// Setup the circle animation.
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
[animation setDuration:0.5];
[animation setRemovedOnCompletion:YES];
[animation setFromValue:@(0)];
[animation setToValue:@(1)];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
[animation setFillMode:kCAFillModeBoth];
    
// Begin the circle animation.
[greenPlayButtonCircle addAnimation:animation forKey:@"drawCircleAnimation"];

This is what the circle looks like initially (set at 100% - which is what I want):

enter image description here

Now I want to reduce the circle percentage or size and this is how I want it to animate:

enter image description here

This is what is actually happening (the entire circle get redrawn which is NOT what I want):

enter image description here

Is there any way to perform the reverse animation?


Solution

  • You can control this with fromValue and toValue properties, e.g. to reduce the circle path from 100% to 80%:

    [animation setFromValue:@(1)];
    [animation setToValue:@(0.8)];