Quartz 2D Programming Guide 涵盖了您需要的一切。我建议你看一下。
但是,将所有内容放在一起可能很困难,因此我将引导您完成。我们将编写一个函数,它接受一个大小并返回一个看起来大致类似于您的片段之一的图像:
我们这样开始函数定义:
static UIImage *imageWithSize(CGSize size) {
我们需要一个常数来表示片段的厚度:
static CGFloat const kThickness = 20;
以及勾画线段的线宽常量:
static CGFloat const kLineWidth = 1;
以及阴影大小的常量:
static CGFloat const kShadowWidth = 8;
接下来我们需要创建一个用于绘制的图像上下文:
UIGraphicsBeginImageContextWithOptions(size, NO, 0); {
我在该行的末尾放了一个左大括号,因为我喜欢额外的缩进,以提醒我稍后致电UIGraphicsEndImageContext。
由于我们需要调用的很多函数都是 Core Graphics(又名 Quartz 2D)函数,而不是 UIKit 函数,我们需要获取CGContext:
CGContextRef gc = UIGraphicsGetCurrentContext();
现在我们已经准备好真正开始了。首先,我们在路径中添加一个弧。弧线沿着我们要绘制的线段的中心延伸:
CGContextAddArc(gc, size.width / 2, size.height / 2,
(size.width - kThickness - kLineWidth) / 2,
-M_PI / 4, -3 * M_PI / 4, YES);
现在我们将要求 Core Graphics 将路径替换为“描边”版本,以勾勒出路径。我们首先将笔画的粗细设置为我们希望段具有的粗细:
CGContextSetLineWidth(gc, kThickness);
和we set the line cap style to “butt” so we'll have squared-off ends:
CGContextSetLineCap(gc, kCGLineCapButt);
然后我们可以要求 Core Graphics 将路径替换为描边版本:
CGContextReplacePathWithStrokedPath(gc);
要用线性渐变填充这条路径,我们必须告诉 Core Graphics 将所有操作裁剪到路径内部。这样做会使 Core Graphics 重置路径,但稍后我们将需要路径在边缘周围绘制黑线。所以我们将路径复制到这里:
CGPathRef path = CGContextCopyPath(gc);
由于我们希望片段投射阴影,因此我们将在进行任何绘制之前设置阴影参数:
CGContextSetShadowWithColor(gc,
CGSizeMake(0, kShadowWidth / 2), kShadowWidth / 2,
[UIColor colorWithWhite:0 alpha:0.3].CGColor);
我们将填充线段(使用渐变)和描边(绘制黑色轮廓)。我们希望两个操作都有一个阴影。我们通过开始一个透明层来告诉 Core Graphics:
CGContextBeginTransparencyLayer(gc, 0); {
我在该行的末尾放了一个左大括号,因为我喜欢有一个额外的缩进级别,以提醒我稍后致电CGContextEndTransparencyLayer。
由于我们要更改上下文的剪辑区域进行填充,但我们不想在稍后描边轮廓时进行剪辑,所以我们需要保存图形状态:
CGContextSaveGState(gc); {
我在该行的末尾放了一个左大括号,因为我喜欢有一个额外的缩进级别,以提醒我稍后致电CGContextRestoreGState。
要用渐变填充路径,我们需要创建一个渐变对象:
CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColors(rgb, (__bridge CFArrayRef)@[
(__bridge id)[UIColor grayColor].CGColor,
(__bridge id)[UIColor whiteColor].CGColor
], (CGFloat[]){ 0.0f, 1.0f });
CGColorSpaceRelease(rgb);
我们还需要确定渐变的起点和终点。我们将使用路径边界框:
CGRect bbox = CGContextGetPathBoundingBox(gc);
CGPoint start = bbox.origin;
CGPoint end = CGPointMake(CGRectGetMaxX(bbox), CGRectGetMaxY(bbox));
我们将强制水平或垂直绘制渐变,以较长者为准:
if (bbox.size.width > bbox.size.height) {
end.y = start.y;
} else {
end.x = start.x;
}
现在我们终于有了绘制渐变所需的一切。首先我们剪辑到路径:
CGContextClip(gc);
然后我们绘制渐变:
CGContextDrawLinearGradient(gc, gradient, start, end, 0);
然后我们可以释放渐变,恢复保存的图形状态:
CGGradientRelease(gradient);
} CGContextRestoreGState(gc);
当我们调用CGContextClip 时,Core Graphics 会重置上下文的路径。路径不是已保存图形状态的一部分;这就是我们之前制作副本的原因。现在是时候使用该副本再次在上下文中设置路径了:
CGContextAddPath(gc, path);
CGPathRelease(path);
现在我们可以描边路径,绘制线段的黑色轮廓:
CGContextSetLineWidth(gc, kLineWidth);
CGContextSetLineJoin(gc, kCGLineJoinMiter);
[[UIColor blackColor] setStroke];
CGContextStrokePath(gc);
接下来我们告诉 Core Graphics 结束透明层。这将使它查看我们绘制的内容并在下面添加阴影:
} CGContextEndTransparencyLayer(gc);
现在我们都画完了。我们要求 UIKit 从图像上下文中创建一个UIImage,然后销毁上下文并返回图像:
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
您可以一起找到代码in this gist。