iOS-限制边界内绘制:仅在闭合路径内绘图且SourceIn模式卡顿问题
解决SourceIn混合模式绘制耗时过长的问题
首先,咱们得搞清楚为什么用SourceIn混合模式会变慢:每次调用draw(_:)时,Core Graphics都会在CPU层面做像素级的混合计算,尤其是触摸移动时draw会频繁触发,这种实时的像素运算很容易导致卡顿。咱们可以换个思路,用Core Animation的图层遮罩来替代混合模式,让GPU来处理遮罩逻辑,效率会高很多。
下面是具体的优化方案:
1. 用CAShapeLayer作为遮罩替代SourceIn混合模式
Core Animation的图层操作是GPU加速的,比Core Graphics的CPU混合高效得多。我们可以把泛洪填充得到的closePath转换成一个CAShapeLayer,作为绘制内容的遮罩,这样绘制的内容只会显示在闭合路径内部,完全不需要依赖混合模式。
实现步骤:
- 提前创建两个图层:一个用来承载你的绘制路径(比如
drawingLayer),一个作为遮罩的maskLayer。 - 当获取到
closePath后,把它设置给maskLayer的path属性,然后把maskLayer赋值给drawingLayer的mask属性。 - 触摸移动时,直接更新
drawingLayer的路径,GPU会自动处理遮罩后的显示,完全避开SourceIn的混合计算。
代码示例:
// 先在类里定义图层属性 private let drawingLayer = CAShapeLayer() private let maskLayer = CAShapeLayer() override func awakeFromNib() { super.awakeFromNib() setupLayers() } private func setupLayers() { // 配置绘制图层 drawingLayer.lineWidth = 10 drawingLayer.lineCap = .round drawingLayer.strokeColor = UIColor.yellow.cgColor layer.addSublayer(drawingLayer) // 配置遮罩图层 maskLayer.fillRule = .evenOdd // 复杂路径下确保遮罩范围正确 drawingLayer.mask = maskLayer } // 当获取到closePath后更新遮罩 func updateClosePathMask(_ closePath: UIBezierPath) { maskLayer.path = closePath.cgPath maskLayer.fillColor = UIColor.black.cgColor // 遮罩填充颜色只要不透明即可 } // 触摸移动时更新绘制路径 func updateDrawingPath(with touchPoints: [CGPoint]) { let path = UIBezierPath() guard let firstPoint = touchPoints.first else { return } path.move(to: firstPoint) for point in touchPoints.dropFirst() { path.addLine(to: point) } drawingLayer.path = path.cgPath // 根据触摸状态切换颜色 drawingLayer.strokeColor = touchEnd ? UIColor.orange.cgColor : UIColor.yellow.cgColor } // 简化draw方法,只保留必要的内容 override func draw(_ rect: CGRect) { drawFloodFill(path: UIBezierPath()) }
2. 优化泛洪填充的绘制
如果drawFloodFill也是耗时操作,建议把它也渲染到一个单独的CALayer(比如floodFillLayer),而不是每次在draw里调用。比如一次性把泛洪填充的结果绘制到位图,然后设置给floodFillLayer的contents属性,避免重复计算。
3. 避免频繁触发draw(_:)
原来的代码里触摸移动时可能会频繁调用setNeedsDisplay(),导致draw反复执行。用Core Animation图层的话,更新path属性不会触发整个视图的重绘,只会更新图层的局部内容,性能提升明显。
为什么这个方案更快?
- Core Animation的图层操作是GPU加速的,遮罩计算由GPU完成,比CPU层面的
SourceIn混合快得多。 - 避免了每次
draw时的像素级混合运算,减少了CPU的负载。 - 图层的更新是局部的,不需要重绘整个视图区域。
内容的提问来源于stack exchange,提问作者Paresh Patel
相关产品推荐
相关产品推荐

