CAShapeLayer/UIBezierPath不同绘制方向时形状交集异常裁剪问题
解决UIBezierPath多方向子路径重叠区域裁剪问题
问题原因
你遇到的裁剪问题源于**非零环绕数填充规则(nonZero)**的特性:当两个子路径绘制方向相反时,重叠区域的路径环绕数会相互抵消(一个+1、一个-1,总和为0),导致该区域不被填充;而方向一致时,重叠区域环绕数累加(总和为2),就能正常填充。
解决方案
要在同一图层用patternImage完整填充所有形状(包括重叠区域),核心是统一所有子路径的绘制方向,确保非零环绕数规则下重叠区域的环绕数不为0。
代码修改示例
将所有圆弧统一为顺时针方向绘制(或统一为逆时针),调整相反方向的圆弧参数即可:
let view = UIView() let path = UIBezierPath() // 第一组:顺时针绘制 path.addArc(withCenter: .init(x: 100, y: 100), radius: 100, startAngle: 0 * .pi, endAngle: 2 * .pi, clockwise: true) path.close() path.addArc(withCenter: .init(x: 200, y: 100), radius: 100, startAngle: 0 * .pi, endAngle: 2 * .pi, clockwise: true) path.close() // 第二组:原逆时针改为顺时针 path.addArc(withCenter: .init(x: 100, y: 300), radius: 100, startAngle: 0 * .pi, endAngle: 2 * .pi, clockwise: true) path.close() path.addArc(withCenter: .init(x: 200, y: 300), radius: 100, startAngle: 0 * .pi, endAngle: 2 * .pi, clockwise: true) path.close() // 第三组:将逆时针圆弧转为顺时针 path.addArc(withCenter: .init(x: 100, y: 500), radius: 100, startAngle: 0 * .pi, endAngle: 2 * .pi, clockwise: true) path.close() path.addArc(withCenter: .init(x: 200, y: 500), radius: 100, startAngle: 0 * .pi, endAngle: 2 * .pi, clockwise: true) path.close() let layer = CAShapeLayer() layer.path = path.cgPath layer.fillColor = UIColor(patternImage: .maskStripes).cgColor layer.fillRule = .nonZero // 保持非零环绕数规则 view.layer.addSublayer(layer)
通用处理方法
如果实际项目中无法提前确定路径方向,可以添加辅助方法统一路径方向:
extension UIBezierPath { func addUnifiedDirectionArc(center: CGPoint, radius: CGFloat, originalClockwise: Bool) { // 统一转为顺时针绘制 if originalClockwise { addArc(withCenter: center, radius: radius, startAngle: 0, endAngle: 2 * .pi, clockwise: true) } else { // 调整角度参数,实现与逆时针相同的形状但统一为顺时针方向 addArc(withCenter: center, radius: radius, startAngle: 2 * .pi, endAngle: 0, clockwise: true) } close() } } // 使用示例 path.addUnifiedDirectionArc(center: .init(x: 100, y: 500), radius: 100, originalClockwise: false) path.addUnifiedDirectionArc(center: .init(x: 200, y: 500), radius: 100, originalClockwise: true)
关键说明
- 不要使用
evenOdd填充规则:该规则会将重叠区域(被路径包围偶数次)视为非填充区域,不符合你需要完整显示所有形状的需求。 - 必须保持同一图层:多个CAShapeLayer会导致patternImage在每个图层独立平铺,出现条纹错位问题,因此所有子路径必须在同一图层绘制。
内容的提问来源于stack exchange,提问作者cloudprogrammer
相关产品推荐
相关产品推荐

