Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
371 views
in Technique[技术] by (71.8m points)

iphone - draw outer half circle with gradient using core graphics in iOS?

i want to draw a shape like in the attached image using core graphics in iOS. Is this possible. Please provide sample code if it possible. enter image description here

I want at least 3 color gradient over the shape.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Gradients don't naturally draw along path. You have to simulate it. The code is using NSBezierPath, NSView and CGContext but it should not be hard to port it to iOS.

I did with an assembly of trapezoids.

Here is the drawRect of the NSView drawing the gradients:

@implementation grad
-(void)drawRect:(NSRect)dirtyRect {

    [[NSColor whiteColor]set];
    NSRectFill([self bounds]);
    float dim = MIN(self.bounds.size.width, self.bounds.size.height);
    int subdiv=512;
    float r=dim/4;
    float R=dim/2;

    float halfinteriorPerim = M_PI*r;
    float halfexteriorPerim = M_PI*R;
    float smallBase= halfinteriorPerim/subdiv;
    float largeBase= halfexteriorPerim/subdiv;

    NSBezierPath * cell = [NSBezierPath bezierPath];

    [cell moveToPoint:NSMakePoint(- smallBase/2, r)];
    [cell lineToPoint:NSMakePoint(+ smallBase/2, r)];

    [cell lineToPoint:NSMakePoint( largeBase /2 , R)];
    [cell lineToPoint:NSMakePoint(-largeBase /2,  R)];
    [cell closePath];

    float incr = M_PI / subdiv;
    CGContextRef ctx = [[NSGraphicsContext currentContext] graphicsPort];
    CGContextTranslateCTM(ctx, +self.bounds.size.width/2, +self.bounds.size.height/2);

    CGContextScaleCTM(ctx, 0.9, 0.9);
    CGContextRotateCTM(ctx, M_PI/2);
    CGContextRotateCTM(ctx,-incr/2);

    for (int i=0;i<subdiv;i++) {
        // replace this color with a color extracted from your gradient object
        [[NSColor colorWithCalibratedHue:(float)i/subdiv saturation:1 brightness:1 alpha:1] set];
        [cell fill];
        [cell stroke];
        CGContextRotateCTM(ctx, -incr);
    }
}

This looks like this, with various combinations of subdiv and r (interior radius), and at different scales.

Gradient along a circle

New version with blocks, iOS ready

This version uses Objective-C blocks for color and contour functions. Just pass in a block a function that returns the inner radius, outer radius, and color for any number between 0 and 1. Other parameters are start angle, end angle, number of subdivisions, center, and a scale for debugging purpose, and a CGContextRef.

#import "GradientView.h"

@implementation GradientView

typedef void (^voidBlock)(void);
typedef float (^floatfloatBlock)(float);
typedef UIColor * (^floatColorBlock)(float);

-(CGPoint) pointForTrapezoidWithAngle:(float)a andRadius:(float)r  forCenter:(CGPoint)p{
    return CGPointMake(p.x + r*cos(a), p.y + r*sin(a));
}

-(void)drawGradientInContext:(CGContextRef)ctx  startingAngle:(float)a endingAngle:(float)b intRadius:(floatfloatBlock)intRadiusBlock outRadius:(floatfloatBlock)outRadiusBlock withGradientBlock:(floatColorBlock)colorBlock withSubdiv:(int)subdivCount withCenter:(CGPoint)center withScale:(float)scale
{
    float angleDelta = (b-a)/subdivCount;
    float fractionDelta = 1.0/subdivCount;

    CGPoint p0,p1,p2,p3, p4,p5;
    float currentAngle=a;
    p4=p0 = [self pointForTrapezoidWithAngle:currentAngle andRadius:intRadiusBlock(0) forCenter:center];
    p5=p3 = [self pointForTrapezoidWithAngle:currentAngle andRadius:outRadiusBlock(0) forCenter:center];
    CGMutablePathRef innerEnveloppe=CGPathCreateMutable(),
    outerEnveloppe=CGPathCreateMutable();

    CGPathMoveToPoint(outerEnveloppe, 0, p3.x, p3.y);
    CGPathMoveToPoint(innerEnveloppe, 0, p0.x, p0.y);
    CGContextSaveGState(ctx);

    CGContextSetLineWidth(ctx, 1);

    for (int i=0;i<subdivCount;i++)
    {
        float fraction = (float)i/subdivCount;
        currentAngle=a+fraction*(b-a);
        CGMutablePathRef trapezoid = CGPathCreateMutable();

        p1 = [self pointForTrapezoidWithAngle:currentAngle+angleDelta andRadius:intRadiusBlock(fraction+fractionDelta) forCenter:center];
        p2 = [self pointForTrapezoidWithAngle:currentAngle+angleDelta andRadius:outRadiusBlock(fraction+fractionDelta) forCenter:center];

        CGPathMoveToPoint(trapezoid, 0, p0.x, p0.y);
        CGPathAddLineToPoint(trapezoid, 0, p1.x, p1.y);
        CGPathAddLineToPoint(trapezoid, 0, p2.x, p2.y);
        CGPathAddLineToPoint(trapezoid, 0, p3.x, p3.y);
        CGPathCloseSubpath(trapezoid);

        CGPoint centerofTrapezoid = CGPointMake((p0.x+p1.x+p2.x+p3.x)/4, (p0.y+p1.y+p2.y+p3.y)/4);

        CGAffineTransform t = CGAffineTransformMakeTranslation(-centerofTrapezoid.x, -centerofTrapezoid.y);
        CGAffineTransform s = CGAffineTransformMakeScale(scale, scale);
        CGAffineTransform concat = CGAffineTransformConcat(t, CGAffineTransformConcat(s, CGAffineTransformInvert(t)));
        CGPathRef scaledPath = CGPathCreateCopyByTransformingPath(trapezoid, &concat);

        CGContextAddPath(ctx, scaledPath);
        CGContextSetFillColorWithColor(ctx,colorBlock(fraction).CGColor);
        CGContextSetStrokeColorWithColor(ctx, colorBlock(fraction).CGColor);
        CGContextSetMiterLimit(ctx, 0);

        CGContextDrawPath(ctx, kCGPathFillStroke);

        CGPathRelease(trapezoid);
        p0=p1;
        p3=p2;

        CGPathAddLineToPoint(outerEnveloppe, 0, p3.x, p3.y);
        CGPathAddLineToPoint(innerEnveloppe, 0, p0.x, p0.y);
    }
    CGContextSetLineWidth(ctx, 10);
    CGContextSetLineJoin(ctx, kCGLineJoinRound);
    CGContextSetStrokeColorWithColor(ctx, [UIColor blackColor].CGColor);
    CGContextAddPath(ctx, outerEnveloppe);
    CGContextAddPath(ctx, innerEnveloppe);
    CGContextMoveToPoint(ctx, p0.x, p0.y);
    CGContextAddLineToPoint(ctx, p3.x, p3.y);
    CGContextMoveToPoint(ctx, p4.x, p4.y);
    CGContextAddLineToPoint(ctx, p5.x, p5.y);
    CGContextStrokePath(ctx);
}

-(void)drawRect:(CGRect)rect {

    CGContextRef ctx = UIGraphicsGetCurrentContext();

    [[UIColor whiteColor] set];
    UIRectFill(self.bounds);

    CGRect r = self.bounds;

    r=CGRectInset(r, 60, 60);

    if (r.size.width > r.size.height)
        r.size.width=r.size.height;
    else r.size.height=r.size.width;

    float radius=r.size.width/2;

    [self drawGradientInContext:ctx  startingAngle:M_PI/16 endingAngle:2*M_PI-M_PI/16 intRadius:^float(float f) {
//        return 0*f + radius/2*(1-f);
        return 200+10*sin(M_PI*2*f*7);
//        return 50+sqrtf(f)*200;
//        return radius/2;
    } outRadius:^float(float f) {
//         return radius *f + radius/2*(1-f);
        return radius;
//        return 300+10*sin(M_PI*2*f*17);
    } withGradientBlock:^UIColor *(float f) {

//        return [UIColor colorWithHue:f saturation:1 brightness:1 alpha:1];
        float sr=90, sg=54, sb=255;
        float er=218, eg=0, eb=255;
        return [UIColor colorWithRed:(f*sr+(1-f)*er)/255. green:(f*sg+(1-f)*eg)/255. blue:(f*sb+(1-f)*eb)/255. alpha:1];

    } withSubdiv:256 withCenter:CGPointMake(CGRectGetMidX(r), CGRectGetMidY(r)) withScale:1];

}

@end

Examples:

Curved gradient 1

Curved gradient 2


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...