iphone - 在 iOS 中使用核心图形绘制带渐变的外半圆?

标签 iphone ios core-graphics

我想在 iOS 中使用核心图形绘制一个形状,如附图所示。这可能吗。如果可能,请提供示例代码。 enter image description here

我希望在形状上至少有 3 种颜色渐变。

最佳答案

渐变不会自然地沿着路径绘制。你必须模拟它。该代码使用了 NSBezierPath、NSView 和 CGContext,但将其移植到 iOS 应该不难。

我做了一组梯形。

这是绘制渐变的 NSView 的 drawRect:

@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);
    }
}

这看起来像这样,具有 subdivr(内部半径)的各种组合,并且具有不同的比例。

Gradient along a circle

带 block 的新版本,iOS 就绪

此版本使用 Objective-C block 来实现颜色和轮廓函数。只需在一个 block 中传递一个函数,该函数返回 0 到 1 之间的任何数字的内半径、外半径和颜色。其他参数是起始角度、结束角度、分割数、中心和用于调试目的的比例,以及一个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

例子:

Curved gradient 1

Curved gradient 2

关于iphone - 在 iOS 中使用核心图形绘制带渐变的外半圆?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11783114/

相关文章:

iphone - 如何使用 AVAssetWriter 更改视频元数据?

iphone:将多点触控从设备发送到模拟器?

ios - 为什么在使用代码将 db 复制到文档文件夹之前,Xcode 会自动复制 db 而它是空的?

ios - 无法让 AdMob 或 iAd 横幅广告在 iOS ActionExtension 或 ShareExtension 中运行

ios - 如何在 iOS 5 中为 CIAffineTransform 设置 inputTransform

iphone - 跨平台移动开发做了哪些工作?

ios - View 未填充数据 AFNetworking

ios - 在 iOS 8 中输入视频时旋转

ios - 在 iOS 上,当我们从上下文中创建一个层并获取层的上下文后,这些上下文如何相互关联?

iphone - iOS 中的 3d 文字效果