将CGGradient剪切为CGPath

时间:2011-01-25 23:08:46

标签: iphone cocoa-touch core-graphics quartz-2d

我一直在撞墙,试图弄清楚为什么这不起作用。

基本上,我试图使用CGPath绘制图形(图表),然后使用它来剪切渐变。最终效果应该像iPhone附带的Stocks应用程序一样。

渐变和路径分别作为两个分层(未剪切)元素精细绘制。但是如果我注释掉CGContextDrawPath,那么行和渐变都不会绘制到屏幕上。

这是我的drawRect代码:

CGContextRef context = UIGraphicsGetCurrentContext();

[[UIColor whiteColor] set];
CGContextSetLineWidth(context, 2.0f);
CGPoint lastDrawnPt = [[points objectAtIndex:0] CGPointValue];
CGPoint firstDrawnPt = lastDrawnPt;
//create the path for the gradient
CGMutablePathRef thePath = CGPathCreateMutable();
CGPathMoveToPoint(thePath, NULL, lastDrawnPt.x, self.bounds.size.height); // bottom left
CGPathAddLineToPoint(thePath, NULL, lastDrawnPt.x, lastDrawnPt.y);


for (int i=0; i<(points.count-1); i++) {
    //CGPoint pt1 = [[points objectAtIndex:i] CGPointValue];
    CGPoint pt2 = [[points objectAtIndex:i+1] CGPointValue];
    if (pt2.x > lastDrawnPt.x+2) {
        // only draw if we've moved sunstantially to the right

        //for the gradient
        CGPathMoveToPoint(thePath, NULL, lastDrawnPt.x, lastDrawnPt.y);
        CGPathAddLineToPoint(thePath, NULL, pt2.x, pt2.y);


        lastDrawnPt = pt2;
    }
}

//finish the gradient clipping path
CGPathMoveToPoint(thePath, NULL, lastDrawnPt.x, lastDrawnPt.y);
CGPathAddLineToPoint(thePath, NULL, lastDrawnPt.x, self.bounds.size.height); // bottom right
CGPathMoveToPoint(thePath, NULL, lastDrawnPt.x, self.bounds.size.height);
CGPathAddLineToPoint(thePath, NULL, firstDrawnPt.x, self.bounds.size.height); // bottom right

CGPathCloseSubpath(thePath);

//add the gradient clipping path to the context
CGContextSaveGState(context);
CGContextAddPath(context, thePath);

//draw the path
float components[4] = {1.0, 1.0, 1.0, 1.0};
CGContextSetStrokeColor(context, components);
CGContextDrawPath(context,kCGPathStroke);

//clip the path
CGContextClip(context);


//Draw Gradient
UIColor *topColor = [UIColor colorWithRed: 1.0 green:1.0 blue:1.0 alpha:1.0];
UIColor *bottomColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.0];
CGColorRef colorRef[] = { [topColor CGColor], [bottomColor CGColor] };
CFArrayRef colors = CFArrayCreate(NULL, (const void**)colorRef, sizeof(colorRef) / sizeof(CGColorRef), &kCFTypeArrayCallBacks);

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, colors, NULL);
CFRelease(colorSpace);
CFRelease(colors);

//  Draw a linear gradient from top to bottom
CGPoint gradStartPoint = CGPointMake(50.0, self.bounds.size.height);
CGPoint gradEndPoint = CGPointMake(50.0, 0.0);
CGContextDrawLinearGradient(context, gradient, gradStartPoint, gradEndPoint, 0);

CFRelease(gradient);

// Cleanup
CGColorSpaceRelease(colorSpace);

CGContextRestoreGState(context);

1 个答案:

答案 0 :(得分:1)

CGPathMoveToPoint(thePath, NULL, lastDrawnPt.x, self.bounds.size.height); // bottom left
CGPathAddLineToPoint(thePath, NULL, lastDrawnPt.x, lastDrawnPt.y);


for (int i=0; i<(points.count-1); i++) {
    //CGPoint pt1 = [[points objectAtIndex:i] CGPointValue];
    CGPoint pt2 = [[points objectAtIndex:i+1] CGPointValue];
    if (pt2.x > lastDrawnPt.x+2) {
        // only draw if we've moved sunstantially to the right

        //for the gradient
        CGPathMoveToPoint(thePath, NULL, lastDrawnPt.x, lastDrawnPt.y);
        CGPathAddLineToPoint(thePath, NULL, pt2.x, pt2.y);


        lastDrawnPt = pt2;
    }
}

//finish the gradient clipping path
CGPathMoveToPoint(thePath, NULL, lastDrawnPt.x, lastDrawnPt.y);
CGPathAddLineToPoint(thePath, NULL, lastDrawnPt.x, self.bounds.size.height); // bottom right
CGPathMoveToPoint(thePath, NULL, lastDrawnPt.x, self.bounds.size.height);
CGPathAddLineToPoint(thePath, NULL, firstDrawnPt.x, self.bounds.size.height); // bottom right

这只是绘制了一系列线段。对于某些点值,它可能看起来像这样:

| |||| |

它不会绘制单个连续形状。因此,这条路径对于剪切是无用的,因为它实际上是空的;正如您所见,剪切到它将导致剪切路径内没有进一步的绘图。

每个linetocurvetoarc等等都是从当前点开始的。您使用moveto设置最初,但每个linetocurvetoarc等都不会清除当前点,它更新它。因此,要创建单个形状,请执行一个moveto后跟一系列lineto(或curvetoarc),最后是closepath

说到closepath ......

CGPathCloseSubpath(thePath);

这会在路径中创建唯一的闭合形状,但由于该形状的区域为零(只是一个自身加倍的线段),因此它仍然无法用于剪切目的。

我怀疑你需要做的就是至少删除一个moveto段(循环中的一段,如果不是那么后面的那段)。然后,您可以简化数组上的循环使用快速枚举,而不是使用索引,并切断跟踪“最后绘制的点”。

此外,NSArray索引的正确类型是NSUInteger,而不是int。保持你的类型匹配 - 它可以避免后来的痛苦。