首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >UIBezierPath减去路径

UIBezierPath减去路径
EN

Stack Overflow用户
提问于 2012-01-14 09:08:25
回答 9查看 31.5K关注 0票数 52

通过使用[UIBezierPath bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:],我能够创建一个圆形视图,如下所示:

如何从这条路径(或其他方式)中减去另一条路径,以创建如下路径:

有没有办法让我做这样的事?伪码:

代码语言:javascript
复制
UIBezierPath *bigMaskPath = [UIBezierPath bezierPathWithRoundedRect:bigView.bounds 
                                 byRoundingCorners:(UIRectCornerTopLeft|UIRectCornerTopRight)
                                       cornerRadii:CGSizeMake(18, 18)];
UIBezierPath *smallMaskPath = [UIBezierPath bezierPathWithRoundedRect:smalLView.bounds 
                                     byRoundingCorners:(UIRectCornerTopLeft|UIRectCornerTopRight)
                                           cornerRadii:CGSizeMake(18, 18)];

UIBezierPath *finalPath = [UIBezierPath pathBySubtractingPath:smallMaskPath fromPath:bigMaskPath];
EN

回答 9

Stack Overflow用户

回答已采纳

发布于 2012-01-14 13:22:51

如果您想要描边减去的路径,您只能靠自己。Apple没有提供返回(或者仅仅是笔划)从一条路径减去另一条路径的API。

如果您只想填充减去的路径(如示例图像中所示),则可以使用裁剪路径进行填充。不过,你必须使用一些技巧。向剪切路径添加路径时,新的剪切路径是旧剪切路径和添加的路径的交集。因此,如果您只是将smallMaskPath添加到剪切路径,最终将只填充smallMaskPath中的区域,这与您想要的相反。

您需要做的是将现有的裁剪路径与smallMaskPath的反向路径相交。幸运的是,使用奇偶缠绕规则可以很容易地做到这一点。您可以在中阅读有关奇偶规则的内容。

基本思想是我们创建一个包含两个子路径的复合路径:您的smallMaskPath和一个巨大的矩形,该矩形完全包围您的smallMaskPath和您可能想要填充的每个其他像素。由于奇偶规则,smallMaskPath内部的每个像素将被视为复合路径的外部,而smallMaskPath外部的每个像素将被视为复合路径的内部。

因此,让我们创建此复合路径。我们将从这个巨大的矩形开始。没有比无限大的矩形更大的矩形了:

代码语言:javascript
复制
UIBezierPath *clipPath = [UIBezierPath bezierPathWithRect:CGRectInfinite];

现在,我们通过向其添加smallMaskPath将其添加到复合路径中:

代码语言:javascript
复制
[clipPath appendPath:smallMaskPath];

接下来,我们将路径设置为使用奇偶规则:

代码语言:javascript
复制
clipPath.usesEvenOddFillRule = YES;

在我们裁剪到这个路径之前,我们应该保存图形状态,这样我们就可以在完成后撤消对裁剪路径的更改:

代码语言:javascript
复制
CGContextSaveGState(UIGraphicsGetCurrentContext()); {

现在我们可以修改剪切路径了:

代码语言:javascript
复制
    [clipPath addClip];

我们可以填满bigMaskPath

代码语言:javascript
复制
    [[UIColor orangeColor] setFill];
    [bigMaskPath fill];

最后,我们恢复图形状态,撤消对剪切路径的更改:

代码语言:javascript
复制
} CGContextRestoreGState(UIGraphicsGetCurrentContext());

下面是所有代码,以防您想要复制/粘贴它:

代码语言:javascript
复制
UIBezierPath *clipPath = [UIBezierPath bezierPathWithRect:CGRectInfinite];
[clipPath appendPath:smallMaskPath];
clipPath.usesEvenOddFillRule = YES;

CGContextSaveGState(UIGraphicsGetCurrentContext()); {
    [clipPath addClip];
    [[UIColor orangeColor] setFill];
    [bigMaskPath fill];
} CGContextRestoreGState(UIGraphicsGetCurrentContext());
票数 63
EN

Stack Overflow用户

发布于 2015-08-25 17:21:23

实际上,对于大多数情况,有一种更简单的方法,例如在Swift中:

代码语言:javascript
复制
path.append(cutout.reversing())

这是因为默认的填充规则是non-zero winding rule

票数 86
EN

Stack Overflow用户

发布于 2012-01-14 15:48:40

这样就可以了,可以根据需要调整大小:

代码语言:javascript
复制
CGRect outerRect = {0, 0, 200, 200};
CGRect innerRect  = CGRectInset(outerRect,  30, 30);

UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:outerRect cornerRadius:10];

[path appendPath:[UIBezierPath bezierPathWithRoundedRect:innerRect cornerRadius:5]];
path.usesEvenOddFillRule = YES;

[[UIColor orangeColor] set];
[path fill];

另一种非常简单的方法来获得你想要的效果是只画外圆,改变颜色,并在它上面画内圆。

票数 34
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8859285

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档