开发者

Draw part of a circle

For an iPhone application I want to draw a circle, that is only for an x percentage filled.

Something like this:

Draw part of a circle

I have no problems calculating the radius, the degrees or the radians, that is no problem. Also drawing the circle is already done. But how do I get the iPhone SDK to draw the part that is filled.

I can draw a rectangle that size, but not p开发者_运维百科art of a circle.

I just want to draw that on a a normal context.

Hope someone can give me any pointers here.


A lot of people have showed you how this can be done in Core Graphics but it can also be done with Core Animation which gives the big addition of easily being able to animate the percentage of the pie shape.

The following code will create both the ring and the partly filled layers (even though you said that you already can draw the ring) since its nice to have both the ring and the pie shape to be drawn using the same method.

If you animate the strokeStart or strokeEnd properties of the pieShape layer you will have the percentage animate. As with all Core Animation code you will need to add QuartzCore.framework to your project and include <QuartzCore/QuartzCore.h> in your code.

// Create a white ring that fills the entire frame and is 2 points wide.
// Its frame is inset 1 point to fit for the 2 point stroke width
CGFloat radius = MIN(self.frame.size.width,self.frame.size.height)/2;
CGFloat inset  = 1;
CAShapeLayer *ring = [CAShapeLayer layer];
ring.path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(self.bounds, inset, inset) 
                                       cornerRadius:radius-inset].CGPath;

ring.fillColor   = [UIColor clearColor].CGColor;
ring.strokeColor = [UIColor whiteColor].CGColor;
ring.lineWidth   = 2;

// Create a white pie-chart-like shape inside the white ring (above).
// The outside of the shape should be inside the ring, therefore the
// frame needs to be inset radius/2 (for its outside to be on 
// the outside of the ring) + 2 (to be 2 points in).
CAShapeLayer *pieShape = [CAShapeLayer layer];
inset = radius/2 + 2; // The inset is updated here
pieShape.path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(self.bounds, inset, inset)
                                        cornerRadius:radius-inset].CGPath;
pieShape.fillColor   = [UIColor clearColor].CGColor;
pieShape.strokeColor = [UIColor whiteColor].CGColor;
pieShape.lineWidth   = (radius-inset)*2;   

// Add sublayers
// NOTE: the following code is used in a UIView subclass (thus self is a view)
// If you instead chose to use this code in a view controller you should instead
// use self.view.layer to access the view of your view controller.
[self.layer addSublayer:ring];
[self.layer addSublayer:pieShape];


Use CGContext's arc functions:

CGContextAddArc(context,
                centerX,
                centerY,
                radius,
                startAngleRadians,
                endAngleRadians,
                clockwise ? 1 : 0);     

See the documentation for CGContextAddArc().


Try this:

CGContextMoveToPoint(the center point)
CGContextAddLineToPoint(the starting point of the fill path on the circumference)
CGContextAddArcToPoint(the ending point of the fill path on the circumference)
CGContextAddLineToPoint(the center point)
CGContextFillPath


I implemented a pie progress view that looks similar to what you are doing. It's open source. Hopefully the source code will help.

SSPieProgressView.h source

SSPieProgressView.m source


CircleViewController.h

#import <UIKit/UIKit.h>

@interface CircleViewController : UIViewController

@end

CircleViewController.m

#import "CircleViewController.h"
#import "GraphView.h"

@interface CircleViewController ()

@end

@implementation CircleViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    GraphView *graphView = [[GraphView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
    graphView.backgroundColor = [UIColor whiteColor];
    graphView.layer.borderColor = [UIColor redColor].CGColor;
    graphView.layer.borderWidth = 1.0f;

    [self.view addSubview:graphView];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

GraphView.h

#import <UIKit/UIKit.h>

@interface GraphView : UIView

@end

GraphView.m

#import "GraphView.h"

@implementation GraphView

- (void)drawRect:(CGRect)rect {

    CGPoint circleCenter = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);

    [self drawCircleWithCircleCenter:(CGPoint) circleCenter radius:80 firstColor:[UIColor blueColor].CGColor secondeColor:[UIColor redColor].CGColor lineWidth:2 startDegree:0 currentDegree:90];
    //[self drawCircleWithCircleCenter2:(CGPoint) circleCenter radius:80 firstColor:[UIColor blueColor].CGColor secondeColor:[UIColor redColor].CGColor lineWidth:2 startDegree:0 currentDegree:90];
}

- (void)drawCircleWithCircleCenter:(CGPoint) circleCenter
                            radius:(CGFloat)radius
                            firstColor:(CGColorRef)firstColor
                            secondeColor:(CGColorRef)secondeColor
                            lineWidth:(CGFloat)lineWidth
                            startDegree:(float)startDegree
                            currentDegree:(float)endDegree {

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetLineWidth(context, lineWidth);

    CGContextMoveToPoint(context, circleCenter.x, circleCenter.y);

    CGContextAddArc(context, circleCenter.x , circleCenter.y, radius, [self radians:startDegree], [self radians:endDegree], 0);
    CGContextSetFillColorWithColor(context, firstColor);
    CGContextFillPath(context);

    CGContextMoveToPoint(context, circleCenter.x, circleCenter.y);

    CGContextAddArc(context, circleCenter.x, circleCenter.y, radius, [self radians:endDegree], [self radians:startDegree], 0);
    CGContextSetFillColorWithColor(context, secondeColor);
    CGContextFillPath(context);
}

- (void)drawCircleWithCircleCenter2:(CGPoint) circleCenter
                            radius:(CGFloat)radius
                        firstColor:(CGColorRef)firstColor
                      secondeColor:(CGColorRef)secondeColor
                         lineWidth:(CGFloat)lineWidth
                       startDegree:(float)startDegree
                     currentDegree:(float)endDegree {

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetLineWidth(context, lineWidth);

    CGContextMoveToPoint(context, circleCenter.x, circleCenter.y);

    CGContextAddArc(context, circleCenter.x , circleCenter.y, radius, [self radians:startDegree], [self radians:endDegree], 0);
    CGContextSetFillColorWithColor(context, firstColor);
    CGContextFillPath(context);

    CGContextMoveToPoint(context, circleCenter.x, circleCenter.y);

    CGContextAddArc(context, circleCenter.x, circleCenter.y, radius, [self radians:endDegree], [self radians:startDegree], 0);
    CGContextSetStrokeColorWithColor(context, secondeColor);
    CGContextStrokePath(context);
}

-(float) radians:(double) degrees {
    return degrees * M_PI / 180;
}


@end

note: you can use one of the 2 methods: "drawCircleWithCircleCenter" or "drawCircleWithCircleCenter2"

this code if you want to split cell on 2 parts only

if you want to split cell on more than 2 parts you can check this : "Drawing a circle ,filled different parts with different color" and check the answer start with this Phrase "we have 6 class"


Well, since nobody used NSBezierPath so far, I figured I could provide the solution I recently used for the same problem:

-(void)drawRect:(NSRect)dirtyRect
{
    double start = -10.0; //degrees
    double end = 190.0; //degrees
    NSPoint center = NSMakePoint(350, 200);
    double radius = 50;

    NSBezierPath *sector = [NSBezierPath bezierPath];
    [sector moveToPoint:center];
    [sector appendBezierPathWithArcWithCenter:center radius:radius startAngle:start endAngle:end];
    [sector lineToPoint:center];
    [sector fill];
}


Below is a full method I am using that does this with Core Graphics, adapting and expanding on mharper's comment above.

This code is for OSX Cocoa, but could easily be changed to iOS, by modifying how you get the context.

- (void)drawPieShapedCircleWithRadius:(CGFloat)radius
                      strokeColor:(CGColorRef)strokeColor
                        fillColor:(CGColorRef)fillColor
                        lineWidth:(CGFloat)lineWidth
                   currentDegrees:(float)currentDegrees
                     startDegrees:(float)startDegrees {
    // get the context
    CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];

    // Set the color of the circle stroke and fill
    CGContextSetStrokeColorWithColor(context, strokeColor);
    CGContextSetFillColorWithColor(context, fillColor);

    // Set the line width of the circle
    CGContextSetLineWidth(context, 1);

    // Calculate the middle of the circle
    CGPoint circleCenter = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2);

    // Move the bezier to the center of the circle
    CGContextMoveToPoint(context, circleCenter.x, circleCenter.y);  // move to the center point

    // Draw the arc from the start point (hardcoded as the bottom of the circle) to the center
    CGContextAddLineToPoint(context, circleCenter.x, circleCenter.y + radius);

    // Draw the arc around the circle from the start degrees point to the current degrees point
    CGContextAddArc(context, circleCenter.x , circleCenter.y, radius, [self radians:startDegrees], [self radians:startDegrees + currentDegrees], 0);

    // Draw the line back into the center of the circle
    CGContextAddLineToPoint(context, circleCenter.x, circleCenter.y);

    // Fill the circle
    CGContextFillPath(context);

    // Draw the line around the circle
    CGContextStrokePath(context);
}


Try this code in a UIView, Example "MyChartClass"...

- (void)drawRect:(CGRect)rect {
    int c=(int)[itemArray count];

    CGFloat angleArray[c];
    CGFloat offset;
    int sum=0;

    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetAllowsAntialiasing(context, false);
    CGContextSetShouldAntialias(context, false);

    for(int i=0;i<[itemArray count];i++) {
        sum+=[[itemArray objectAtIndex:i] intValue];
    }

    for(int i=0;i<[itemArray count];i++) {
        angleArray[i]=(float)(([[itemArray objectAtIndex:i] intValue])/(float)sum)*(2*3.14); 
        CGContextMoveToPoint(context, radius, radius);
        if(i==0)
            CGContextAddArc(context, radius, radius, radius, 0,angleArray[i], 0);
        else
            CGContextAddArc(context, radius, radius, radius,offset,offset+angleArray[i], 0);
        offset+=angleArray[i];

        CGContextSetFillColorWithColor(context, ((UIColor *)[myColorArray objectAtIndex:i]).CGColor);
        CGContextClosePath(context); 
        CGContextFillPath(context);

    }   
}

Implementation in your UIViewController

MyChartClass *myChartClass=[[MyChartClass alloc]initWithFrame:CGRectMake(0, 0, 200, 200)];
myChartClass.backgroundColor = [UIColor clearColor];
myChartClass.itemArray=[[NSArray alloc]initWithObjects:@"75",@"25", nil];
myChartClass.myColorArray=[[NSArray alloc]initWithObjects:[UIColor blackColor],[UIColor whiteColor], nil];
myChartClass.radius=100;
[self.view addSubview:myChartClass];

Regards.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜