objective-cdrawingquartz-2dgeometry

Objective-C Draw a Circle with a Ring shape


I wrote this class that draws a animated progress with a circle (it draws a circular sector based on a float progress)

@implementation MXMProgressView

@synthesize progress;

- (id)initWithDefaultSize {
    int circleOffset = 45.0f;
    self = [super initWithFrame:CGRectMake(0.0f,
                                           0.0f,
                                           135.0f + circleOffset,
                                           135.0f + circleOffset)];
    self.backgroundColor = [UIColor clearColor];
    return self;
}

- (void)drawRect:(CGRect)rect {

    CGRect allRect = self.bounds;
    CGRect circleRect = CGRectMake(allRect.origin.x + 2, allRect.origin.y + 2, allRect.size.width - 4,
                                   allRect.size.height - 4);

    CGContextRef context = UIGraphicsGetCurrentContext();

    // background image
    //UIImage *image = [UIImage imageNamed:@"loader_disc_hover.png"]; 
    //[image drawInRect:circleRect];

    // Orange: E27006
    CGContextSetRGBFillColor(context, 
                             ((CGFloat)0xE2/(CGFloat)0xFF),
                             ((CGFloat)0x70/(CGFloat)0xFF),
                             ((CGFloat)0x06/(CGFloat)0xFF),
                             0.01f); // fill

    //CGContextSetLineWidth(context, 2.0);
    CGContextFillEllipseInRect(context, circleRect);
    //CGContextStrokeEllipseInRect(context, circleRect);

    // Draw progress
    float x = (allRect.size.width / 2);
    float y = (allRect.size.height / 2);

    // Orange: E27006
    CGContextSetRGBFillColor(context, 
                             ((CGFloat)0xE2/(CGFloat)0xFF),
                             ((CGFloat)0x70/(CGFloat)0xFF),
                             ((CGFloat)0x06/(CGFloat)0xFF),
                             1.0f); // progress

    CGContextMoveToPoint(context, x, y);
    CGContextAddArc(context, x, y, (allRect.size.width - 4) / 2, -M_PI_2, (self.progress * 2 * M_PI) - M_PI_2, 0);
    CGContextClosePath(context);
    CGContextFillPath(context);
}

@end

Now what I want to do I to draw a ring shape with the same progress animation, instead of filling the full circle, so a circular sector again not starting from the center of the circle.

I tried with CGContextAddEllipseInRect and the CGContextEOFillPath(context);

with no success.


Solution

  • I think you'll need to construct a more complex path, something like:

    // Move to start point of outer arc  (which might not be required)
    CGContextMoveToPoint(context, x+outerRadius*cos(startAngle), y+outerRadius*sin(startAngle));
    // Add outer arc to path (counterclockwise)
    CGContextAddArc(context, x, y, outerRadius, startAngle, endAngle, 0);
    // move *inward* to start point of inner arc
    CGContextMoveToPoint(context, x+innerRadius*cos(endAngle), y+innerRadius*sin(endAngle));
    // Add inner arc to path (clockwise)
    CGContextAddArc(context, x, y, innerRadius, endAngle, StartAngle, 1);
    // Close the path from end of inner arc to start of outer arc
    CGContextClosePath(context);
    

    Note: I haven't tried the above code myself