Draw circle with UIBezierPath

Mosbah picture Mosbah · Sep 23, 2014 · Viewed 34.3k times · Source

I'm trying to draw a circle using UIBezierPath addArcWithCenter method :

UIBezierPath *bezierPath = 
  [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0., 0., 100., 100.)];

[bezierPath addArcWithCenter:center 
                      radius:0. 
                  startAngle:0 endAngle:2 * M_PI clockwise:YES];

CAShapeLayer *progressLayer = [[CAShapeLayer alloc] init];

[progressLayer setPath:bezierPath.CGPath];
[progressLayer setStrokeColor:[UIColor colorWithWhite:1. alpha:.2].CGColor];
[progressLayer setFillColor:[UIColor clearColor].CGColor];
[progressLayer setLineWidth:.3 * self.bounds.size.width];
[progressLayer setStrokeStart:_volumeValue/100.];
[progressLayer setStrokeEnd:volume/100.]; // between 0 and 100

[_circleView.layer addSublayer:progressLayer];

but what I get is the following :

enter image description here

I tried to play with the different parameters but no luck

Thank you

UPDATE :

I'm sorry if I didn't explain what I'm trying to do:

*The background circle is drawed using :

[UIBezierPath bezierPathWithOvalInRect:CGRectMake(0., 0., 100., 100.)]

*I'm trying to draw the red circle step by step using bezierPathWithOvalInRect between 2 values : _volumeValue and volume

But I can't get a perfect circle, instead I get the horizontale part after certain value.

enter image description here

Answer

Fogmeister picture Fogmeister · Sep 23, 2014

OK, try this...

UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath addArcWithCenter:center radius:50 startAngle:0 endAngle:2 * M_PI clockwise:YES];

CAShapeLayer *progressLayer = [[CAShapeLayer alloc] init];
[progressLayer setPath:bezierPath.CGPath];
[progressLayer setStrokeColor:[UIColor colorWithWhite:1.0 alpha:0.2].CGColor];
[progressLayer setFillColor:[UIColor clearColor].CGColor];
[progressLayer setLineWidth:0.3 * self.bounds.size.width];
[progressLayer setStrokeEnd:volume/100];
[_circleView.layer addSublayer:progressLayer];

volume should be between 0 and 100.

Also, you were creating a path with an ellipse and then adding an arc to it. Don't do that. Just add the arc to the empty path.

If you want to change where the arc starts from then change the startAngle and endAngle when adding the arc. Don't change the stroke start value.

Animating change

[CATransaction begin];
CABasicAnimation *animateStrokeDown = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
animateStrokeDown.toValue = [NSNumber numberWithFloat:volume/100.];
[progressLayer addAnimation:animateStrokeDown forKey:@"animateStrokeDown"];
[CATransaction commit];

OK, what this will do is animate the strokeEnd property of the path. You have to realise though, it works like this...

Begin state: start = 0, end = 6
0123456
-------

// increase volume
Animate to: end = 9
0123456789
----------

// decrease volume
Animate to: end = 1
01
--

The start has not moved. The end has moved. You are not "filling in" the rest of the line. You are changing the line.

This is why the start should always be 0 and you just change the stroke end.