在iOS中使用核心graphics绘制外梯半圈的梯度?

我想在iOS中使用核心graphics绘制附加图像的形状。 这可能吗。 如果可能,请提供示例代码。 在这里输入图像说明

我想在形状上至less有3个颜色渐变。

如果你想在CGContext绘制它:

使用+[UIBezierPath bezierPathWithArcCenter:radius:startAngle:endAngle:clockwise:]创build包含半圆弧的path。 然后使用CGPathCreateCopyByStrokingPath在圆弧周围创build一个封闭的形状。 使用CGContextAddPath将此封闭的形状添加到上下文的path,然后使用CGContextClip将剪辑区域设置为粗圆弧。

使用CGGradientCreateWithColors创build一个彩虹色的CGGradient 。 使用CGContextDrawLinearGradient用渐变填充剪辑区域。

如果你想使用CALayer绘制这个:

创build一个CAGradientLayer 。 将图层的colors属性设置为彩虹的颜色。 将图层的startPoint设置为(0,0),将图层的endPoint为(1,0)。

创build一个CAShapeLayer并将其设置为渐变图层的蒙版。 使用+[UIBezierPath bezierPathWithArcCenter:radius:startAngle:endAngle:clockwise:]CGPathCreateCopyByStrokingPath创build一个包含粗圆弧的path,并将此path设置为形状图层的path

渐变不会自然地沿着path。 你必须模拟它。 代码是使用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 (内半径)的各种组合,并且在不同的尺度上。

渐变沿着一个圆圈

带有块的新版本,iOS就绪

该版本使用Objective-C块进行颜色和轮廓函数。 只需要传入一个函数,该函数返回0到1之间的任意数字的内半径,外半径和颜色。其他参数是开始angular度,结束angular度,细分数,中心和用于debugging的刻度,以及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(px + r*cos(a), py + 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 = (ba)/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*(ba); 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 

例子:

曲线渐变1

弯曲的渐变2

从iOS 8开始,绘制圆形渐变的最简单和最快速的方法就是使用Core Image滤镜。 一个内核链接到这个答案的评论,但是由于搞清楚如何实际使用它花了我一会儿,我会在这里发布整个过程。

实质上,核心图像滤镜是在input图像的每个像素上运行的小片段着色器。 虽然它们被devise用于过滤图像,但您可以通过简单地忽略filter内核中的input像素值来使用它们来生成图像。

下面的代码生成一个虚拟图像作为input,然后将一个自定义的CI内核应用到它以创build一个圆形渐变。

 // 1 - generate a dummy image of the required size UIGraphicsBeginImageContextWithOptions(CGSizeMake(512.0, 256.0), NO, [[UIScreen mainScreen] scale]); CIImage *dummyImage = [CIImage imageWithCGImage:UIGraphicsGetImageFromCurrentImageContext().CGImage]; // 2 - define the kernel algorithm NSString *kernelString = @"kernel vec4 circularGradientKernel(__color startColor, __color endColor, vec2 center, float innerR, float outerR) { \n" " vec2 point = destCoord() - center;" " float rsq = point.x * point.x + point.y * point.y;" " float theta = mod(atan(point.y, point.x), radians(360.0));" " return (rsq > innerR*innerR && rsq < outerR*outerR) ? mix(startColor, endColor, theta/radians(360.0)*2.0) : vec4(0.0, 0.0, 0.0, 1.0);" "}"; // 3 - initialize a Core Image context and the filter kernel CIContext *context = [CIContext contextWithOptions:nil]; CIColorKernel *kernel = [CIColorKernel kernelWithString:kernelString]; // 4 - argument array, corresponding to the first line of the kernel string NSArray *args = @[ [CIColor colorWithRed:1.0 green:0.0 blue:0.0], [CIColor colorWithRed:0.0 green:0.0 blue:1.0], [CIVector vectorWithCGPoint:CGPointMake(CGRectGetMidX(dummyImage.extent),CGRectGetMinY(dummyImage.extent))], [NSNumber numberWithFloat:250.0], [NSNumber numberWithFloat:500.0]]; // 5 - apply the kernel to our dummy image, and convert the result to a UIImage CIImage *ciOutputImage = [kernel applyWithExtent:dummyImage.extent arguments:args]; CGImageRef cgOutput = [context createCGImage:ciOutputImage fromRect:ciOutputImage.extent]; UIImage *gradientImage = [UIImage imageWithCGImage:cgOutput]; CGImageRelease(cgOutput); 

输出如下所示:

使用核心图像过滤器生成的循环渐变。

颜色和中心点以CIColorCIVector的forms传递,内外圆的半径以浮点forms给出。 如果你想传入其他参数,你当然可以修改参数列表。

这种方法甚至可以用于animation,但是如果要这样做的话,确保每个帧都使用相同的上下文 ,因为创build和拆分是性能瓶颈。 只要确保你的animation参数是一个input参数,然后循环执行步骤4和5。

另外,不要忘记最后调用CGImageRelease ,否则你会发生内存泄漏。

我使用了Antoine的答案,并针对iOS进行了调整:

 -(void)drawRect:(CGRect)rect { // http://stackoverflow.com/a/12775798/129202 CGContextRef context = UIGraphicsGetCurrentContext(); [[UIColor whiteColor] set]; //[[NSColor whiteColor]set]; UIRectFill([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; UIBezierPath * cell = [UIBezierPath bezierPath]; [cell moveToPoint:CGPointMake(- smallBase/2, r)]; [cell addLineToPoint:CGPointMake(+ smallBase/2, r)]; [cell addLineToPoint:CGPointMake( largeBase /2 , R)]; [cell addLineToPoint:CGPointMake(-largeBase /2, R)]; [cell closePath]; float incr = M_PI / subdiv; //CGContextRef ctx = [[NSGraphicsContext currentContext] graphicsPort]; CGContextTranslateCTM(context, +self.bounds.size.width/2, +self.bounds.size.height/2); CGContextScaleCTM(context, 0.9, 0.9); CGContextRotateCTM(context, M_PI/2); CGContextRotateCTM(context,-incr/2); for (int i=0;i<subdiv;i++) { // replace this color with a color extracted from your gradient object [[UIColor colorWithHue:(float)i/subdiv saturation:1 brightness:1 alpha:1] set]; [cell fill]; [cell stroke]; CGContextRotateCTM(context, -incr); } } 

作为另一个答案,我发现这个: https : //github.com/paiv/AngleGradientLayer

我试了一下,效果很好。 我没有看到实施。 我不认为我需要。 🙂

此时的代码:

 // // The MIT License (MIT) // // Copyright (C) 2012 Pavel Ivashkov // // Permission is hereby granted, free of charge, to any person obtaining a copy of this // software and associated documentation files (the "Software"), to deal in the Software // without restriction, including without limitation the rights to use, copy, modify, merge, // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons // to whom the Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all copies or // substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. // // // AngleGradientLayer.m // paiv // // Created by Pavel Ivashkov on 2012-02-12. // #import "AngleGradientLayer.h" #if __has_feature(objc_arc) #define BRIDGE_CAST(T) (__bridge T) #else #define BRIDGE_CAST(T) (T) #endif #define byte unsigned char #define F2CC(x) ((byte)(255 * x)) #define RGBAF(r,g,b,a) (F2CC(r) << 24 | F2CC(g) << 16 | F2CC(b) << 8 | F2CC(a)) #define RGBA(r,g,b,a) ((byte)r << 24 | (byte)g << 16 | (byte)b << 8 | (byte)a) #define RGBA_R(c) ((uint)c >> 24 & 255) #define RGBA_G(c) ((uint)c >> 16 & 255) #define RGBA_B(c) ((uint)c >> 8 & 255) #define RGBA_A(c) ((uint)c >> 0 & 255) @interface AngleGradientLayer() - (CGImageRef)newImageGradientInRect:(CGRect)rect; @end static void angleGradient(byte* data, int w, int h, int* colors, int colorCount, float* locations, int locationCount); @implementation AngleGradientLayer - (id)init { if (!(self = [super init])) return nil; self.needsDisplayOnBoundsChange = YES; return self; } #if !__has_feature(objc_arc) - (void)dealloc { [_colors release]; [_locations release]; [super dealloc]; } #endif - (void)drawInContext:(CGContextRef)ctx { CGContextSetFillColorWithColor(ctx, self.backgroundColor); CGRect rect = CGContextGetClipBoundingBox(ctx); CGContextFillRect(ctx, rect); CGImageRef img = [self newImageGradientInRect:rect]; CGContextDrawImage(ctx, rect, img); CGImageRelease(img); } - (CGImageRef)newImageGradientInRect:(CGRect)rect { return [[self class] newImageGradientInRect:rect colors:self.colors locations:self.locations]; } + (CGImageRef)newImageGradientInRect:(CGRect)rect colors:(NSArray *)colors locations:(NSArray *)locations { int w = CGRectGetWidth(rect); int h = CGRectGetHeight(rect); int bitsPerComponent = 8; int bpp = 4 * bitsPerComponent / 8; int byteCount = w * h * bpp; int colorCount = (int)colors.count; int locationCount = (int)locations.count; int* cols = NULL; float* locs = NULL; if (colorCount > 0) { cols = calloc(colorCount, bpp); int *p = cols; for (id cg in colors) { CGColorRef c = BRIDGE_CAST(CGColorRef)cg; float r, g, b, a; size_t n = CGColorGetNumberOfComponents(c); const CGFloat *comps = CGColorGetComponents(c); if (comps == NULL) { *p++ = 0; continue; } r = comps[0]; if (n >= 4) { g = comps[1]; b = comps[2]; a = comps[3]; } else { g = b = r; a = comps[1]; } *p++ = RGBAF(r, g, b, a); } } if (locationCount > 0 && locationCount == colorCount) { locs = calloc(locationCount, sizeof(locs[0])); float *p = locs; for (NSNumber *n in locations) { *p++ = [n floatValue]; } } byte* data = malloc(byteCount); angleGradient(data, w, h, cols, colorCount, locs, locationCount); if (cols) free(cols); if (locs) free(locs); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Little; CGContextRef ctx = CGBitmapContextCreate(data, w, h, bitsPerComponent, w * bpp, colorSpace, bitmapInfo); CGColorSpaceRelease(colorSpace); CGImageRef img = CGBitmapContextCreateImage(ctx); CGContextRelease(ctx); free(data); return img; } @end static inline byte blerp(byte a, byte b, float w) { return a + w * (b - a); } static inline int lerp(int a, int b, float w) { return RGBA(blerp(RGBA_R(a), RGBA_R(b), w), blerp(RGBA_G(a), RGBA_G(b), w), blerp(RGBA_B(a), RGBA_B(b), w), blerp(RGBA_A(a), RGBA_A(b), w)); } static inline int multiplyByAlpha(int c) { float a = RGBA_A(c) / 255.0; return RGBA((byte)(RGBA_R(c) * a), (byte)(RGBA_G(c) * a), (byte)(RGBA_B(c) * a), RGBA_A(c)); } void angleGradient(byte* data, int w, int h, int* colors, int colorCount, float* locations, int locationCount) { if (colorCount < 1) return; if (locationCount > 0 && locationCount != colorCount) return; int* p = (int*)data; float centerX = (float)w / 2; float centerY = (float)h / 2; for (int y = 0; y < h; y++) for (int x = 0; x < w; x++) { float dirX = x - centerX; float dirY = y - centerY; float angle = atan2f(dirY, dirX); if (dirY < 0) angle += 2 * M_PI; angle /= 2 * M_PI; int index = 0, nextIndex = 0; float t = 0; if (locationCount > 0) { for (index = locationCount - 1; index >= 0; index--) { if (angle >= locations[index]) { break; } } if (index >= locationCount) index = locationCount - 1; nextIndex = index + 1; if (nextIndex >= locationCount) nextIndex = locationCount - 1; float ld = locations[nextIndex] - locations[index]; t = ld <= 0 ? 0 : (angle - locations[index]) / ld; } else { t = angle * (colorCount - 1); index = t; t -= index; nextIndex = index + 1; if (nextIndex >= colorCount) nextIndex = colorCount - 1; } int lc = colors[index]; int rc = colors[nextIndex]; int color = lerp(lc, rc, t); color = multiplyByAlpha(color); *p++ = color; } } 

我花了很长的时间寻找如何做到这一点,所以我认为我会这样做。 原来这两个答案都很好的回答了这个问题:

从圆圈或圆环画出细分

为了我的目的,我只使用了该答案的绘图和渐变部分。 结构看起来或多或less像这样…

 CGContextRef context = UIGraphicsGetCurrentcontext(); CGFloat arcStartAngle = M_PI; CGFloat arcEndAngle = 2 * M_PI; CGPoint startPoint = CGPointMake(...); CGPoint endPoint = CGPointMake(...); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGFloat colors[] = { 1.0, 0.0, 0.0, 1.0, //RGBA values (so red to green in this case) 0.0, 1.0, 0.0, 1.0 }; CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, colors, NULL, 2); //Where the 2 is for the number of color components. You can have more colors throughout //your gradient by adding to the colors[] array, and changing the components value. CGColorSpaceRelease(colorSpace); //Now for the arc part... CGMutablePathRef arc = CGPathCreateMutable(); CGPathMoveToPoint(arc, NULL, startPoint.x, startPoint.y); //Here, the CGPoint self.arcCenter is the point around which the arc is placed, so maybe the //middle of your view. self.radius is the distance between this center point and the arc. CGPathAddArc(arc, NULL, self.arcCenter.x, self.arcCenter.y, self.radius, arcStartAngle, arcEndAngle, YES); //This essentially draws along the path in an arc shape CGPathRef strokedArc = CGPathCreateCopyByStrokingPath(arc, NULL, 5.0f, kCGLineCapButt, kCGLineJoinMiter, 10); CGContextSaveGState(context); CGContextAddPath(context, strokedArc); CGContextClip(context); CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0); CGContextDrawPath(context, kCGPathFillStroke); CGGradientRelease(gradient); CGContextRestoreGState(context); //This all draws a gradient that is much larger than the arc itself, but using //CGContextClip, it clips out everything EXCEPT the colors in the arc. Saving and Restoring //the state allows you to preserve any other drawing going on. If you didn't use these, //then all other drawing would also be clipped. 

我希望这有帮助。 如果有任何不清楚的地方,我build议你查看上面的问题链接。 这个问题的答案包含了我在这个答案中使用的一切,以及一些更加有用的绘图技巧。

我已经使用了alecail的答案(iOS中带有块),但是,我注意到它需要一些调整(只需在 – (void)drawGratientInContext:…中添加一些CGPathRelease()),因为它使用了太多记忆。 对不起,我会张贴这个评论,但由于我没有50 +的声誉,我必须回答如下:

 -(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 = (ba)/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*(ba); 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); p0=p1; p3=p2; CGPathAddLineToPoint(outerEnveloppe, 0, p3.x, p3.y); CGPathAddLineToPoint(innerEnveloppe, 0, p0.x, p0.y); //Release both CGPathRefs. The original code just released //trapezoid CG . CGPathRelease(trapezoid); CGPathRelease(scaledPath); } //stroke width CGContextSetLineWidth(ctx, 0.0001); 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); //Release CGPathRefs CGPathRelease(innerEnveloppe); CGPathRelease(outerEnveloppe); }