Swift中如何反转Core Graphics Context绘图效果?
实现UIView绘图反转效果的解决方案
问题背景
现有基于UIView的绘图功能,通过lines数组存储用户绘制的路径信息,需实现点击按钮后反转绘图区域:原本绘制的区域隐藏,未绘制的区域显示。
最优解决方案:利用Core Graphics奇偶填充规则(Even-Odd)
这种方法无需修改现有lines数组结构,仅通过切换重绘逻辑实现反转,符合单次点击重绘的需求,效率更高。
步骤1:添加反转状态变量
在CanvasView类中新增布尔变量,控制当前是否处于反转模式:
class CanvasView: UIView { // ... 原有代码 ... var isInverted = false // 控制反转状态 // ... 原有代码 ... }
步骤2:修改inverse()方法
切换反转状态并触发重绘:
func inverse() { isInverted.toggle() setNeedsDisplay() }
步骤3:重写draw(_ rect:)方法
根据反转状态切换渲染逻辑:
override func draw(_ rect: CGRect) { super.draw(rect) guard let context = UIGraphicsGetCurrentContext() else { return } if isInverted { // 反转模式:先填充整个视图为绘制色,再用奇偶规则挖掉已绘制路径 context.setFillColor(strokeColor.cgColor) context.fill(rect) // 合并所有线条的描边路径(将线条的描边区域转为可填充的路径) let combinedPath = UIBezierPath() vm.lines.forEach { line in let path = UIBezierPath() guard let firstPoint = line.points.first else { return } path.move(to: firstPoint) line.points.dropFirst().forEach { path.addLine(to: $0) } // 配置线条样式(与正常绘制一致) path.lineWidth = line.strokeWidth path.lineCapStyle = .round path.lineJoinStyle = .round // 将描边路径转为填充路径,加入复合路径 combinedPath.append(path.stroke()) } // 使用奇偶裁剪规则,挖掉线条覆盖的区域 context.saveGState() context.addPath(combinedPath.cgPath) context.clip(using: .evenOdd) // 填充背景色,实现“未绘制区域显示”的反转效果 context.setFillColor(self.backgroundColor?.cgColor ?? UIColor.black.cgColor) context.fill(rect) context.restoreGState() } else { // 正常绘图模式:原有逻辑不变 vm.lines.forEach { line in context.setStrokeColor(line.strokeColor.cgColor) context.setLineWidth(line.strokeWidth) context.setLineCap(.round) context.setLineJoin(.round) for (index, point) in line.points.enumerated() { if index == 0 { context.move(to: point) } else { context.addLine(to: point) } } context.strokePath() } } }
原理说明
- 反转模式下,先将整个视图填充为用户绘制时的颜色(比如白色)。
- 把所有用户绘制的线条转换为描边区域的填充路径(因为线条是有宽度的,需要准确获取它覆盖的区域)。
- 使用
evenOdd裁剪规则:该规则会交替显示路径内外的区域,这里通过裁剪掉线条覆盖的区域,再填充背景色,最终实现“未绘制区域显示、已绘制区域隐藏”的反转效果。
不推荐的方案:基于Lines数组计算反转路径
直接计算未绘制区域(整个视图减去所有线条区域)的逻辑非常复杂,尤其是线条带有圆角描边时,需要处理大量路径运算,容易出现精度问题且性能较差,因此不建议采用。
内容的提问来源于stack exchange,提问作者Deltrin Sam
相关产品推荐
相关产品推荐

