You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift Combine下UIBezierPath合并后反转实现子路径镂空的问题问询

解决UIBezierPath多子路径镂空问题的两种可行方案

你遇到的问题本质是UIBezierPath.append(_:)仅做子路径拼接,不会处理路径间的重叠区域,直接对拼接后的路径调用reversing()依然是每个子路径单独反转,相交区域的缠绕计数会不符合镂空预期。以下是可落地的解决方案:


方案1:先对圆形路径做并集运算,再反转镂空

先把所有圆形路径合并为无内部重叠的单一路径,再整体反转追加到矩形路径中,即可实现你要的效果。

  • iOS 16+/macOS 13+可直接使用系统自带的路径布尔运算API,示例代码如下:
import UIKit

let circlePaths: [UIBezierPath] = ...
let rectanglePath: UIBezierPath = ... // 你的基础矩形路径

// 第一步:所有圆形路径执行并集合并,得到无内部重叠的单一路径
var mergedCirclePath: UIBezierPath = .init()
for circle in circlePaths {
    mergedCirclePath = mergedCirclePath.union(circle)
}

// 第二步:合并后的圆形路径整体反转后追加到矩形路径
rectanglePath.append(mergedCirclePath.reversing())

// 渲染时用默认的非零填充规则即可生效
let shapeLayer = CAShapeLayer()
shapeLayer.path = rectanglePath.cgPath
shapeLayer.fillRule = .nonZero
  • 若要支持更低系统版本,可以引入开源路径运算库ClippingBezier,调用对应并集方法合并路径即可,逻辑和上述代码一致。

方案2:用奇偶填充规则直接实现镂空(兼容性更好)

如果不想处理路径布尔运算和反转逻辑,直接修改填充规则即可实现需求,无需调整路径拼接逻辑:

let circlePaths: [UIBezierPath] = ...
let rectanglePath: UIBezierPath = ... 

let totalPath: UIBezierPath = .init()
for path in circlePaths {
  totalPath.append(path)
}
rectanglePath.append(totalPath)

// 渲染时指定奇偶填充规则
let shapeLayer = CAShapeLayer()
shapeLayer.path = rectanglePath.cgPath
shapeLayer.fillRule = .evenOdd

该规则下,路径重叠次数为偶数的区域会自动被镂空,正好符合你要的所有圆形区域(包括重叠区域)从矩形中挖空的需求。如果是用UIGraphics直接绘制,设置rectanglePath.usesEvenOddFillRule = true后再填充即可。


内容的提问来源于stack exchange,提问作者Janosch Hübner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 01:54:03