iOS:CoreGraphics - 使用 CGContextClip 和 lineCap = .Round 剪切弧

iOS: CoreGraphics - Clipping an Arc with CGContextClip and lineCap = .Round

我有一个圆弧,我画的如下:

    func drawBackgroundMask(context: CGContextRef,
                        center: CGPoint,
                        radius: CGFloat,
                        lineWidth: CGFloat,
                        startAngle: CGFloat,
                        endAngle: CGFloat) {
    let adjustedRadius: CGFloat = radius - (lineWidth/2) - 0

    CGContextSetLineWidth(context, lineWidth)
    CGContextSetLineCap(context, .Round)

    CGContextAddArc(context,
                    center.x,
                    center.y,
                    adjustedRadius,
                    startAngle,
                    endAngle,
                    0)

    //CGContextClosePath(context)
    //CGContextClip(context)
    CGContextStrokePath(context)

}

注释掉上面几行后,我可以创建以下内容:

但是,如果我尝试通过取消注释上面的两行代码然后将背景绘制为实体来使用绘制的形状作为遮罩,我会得到不同的结果:

    func drawBackgroundMask(context: CGContextRef,
                        center: CGPoint,
                        radius: CGFloat,
                        lineWidth: CGFloat,
                        startAngle: CGFloat,
                        endAngle: CGFloat) {
    let adjustedRadius: CGFloat = radius - (lineWidth/2) - 0

    CGContextSetLineWidth(context, lineWidth)
    CGContextSetLineCap(context, .Round)

    CGContextAddArc(context,
                    center.x,
                    center.y,
                    adjustedRadius,
                    startAngle,
                    endAngle,
                    0)

    CGContextClosePath(context)
    CGContextClip(context)
    CGContextStrokePath(context)

    CGContextSetRGBFillColor(context, 100.0/255.0, 100.0/255.0, 100.0/255.0, 1.0);
    CGContextFillRect(context, rect);
}

任何人都可以向我解释为什么使用绘制的弧线作为剪贴蒙版导致它的处理方式与绘制的方式不同吗?另外,任何人都可以告诉我创建圆角弧形面具的正确方法吗?这个问题是我正在处理的一个更大的控件的一部分,我必须在其中剪辑另一个具有弧形显示形状的弧。

在你的第二个例子中,剪辑只考虑了圆弧的路径。线宽、笔帽等各种描边参数仅在您实际描边路径时使用,而您并没有这样做。

首先在 CGContext 中设置路径,然后剪辑它。上下文中的路径随后被使用。正如 the documentation 所说:

After determining the new clipping path, the function resets the context’s current path to an empty path.

所以当你调用CGContextStrokePath时,它是没有效果的,因为此时CGContext中的当前路径是空的。

听起来您想在剪辑之前使用 CGContextReplacePathWithStrokedPath。该文档甚至提到了这个确切的用例:

For example, you can clip to the stroked version of a path by calling this function followed by a call to the function CGContextClip.

func drawBackgroundMask(context: CGContextRef,
                    center: CGPoint,
                    radius: CGFloat,
                    lineWidth: CGFloat,
                    startAngle: CGFloat,
                    endAngle: CGFloat) {
    let adjustedRadius: CGFloat = radius - (lineWidth/2) - 0

    CGContextSetLineWidth(context, lineWidth)
    CGContextSetLineCap(context, .Round)

    CGContextAddArc(context,
                    center.x,
                    center.y,
                    adjustedRadius,
                    startAngle,
                    endAngle,
                    0)

    CGContextReplacePathWithStrokedPath(context)
    CGContextClip(context)

    CGContextSetRGBFillColor(context, 100.0/255.0, 100.0/255.0, 100.0/255.0, 1.0);
    CGContextFillRect(context, rect);
}