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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 06:06:05