有几种可能的方法。例如,可以使用纯矢量方法。但是,单个图纸的转换可能非常耗时。
更务实的做法可能如下:
接近
您可以定义一个 Bézier 路径列表 (UIBezierPath),每个路径描述一个可以独立绘制的区域。
贝塞尔路径有两个用途:
如何在黑线内完美绘制
如果您使给定绘图的背景透明,您可以创建用户的绘图操作,并在黑线绘图下方进行剪切。这意味着 Bézier 路径不必完美,只要足够准确即可。
图层/剪辑
接下来的步骤是:
- 最初显示给定的图形
- 确定用户开始绘制的贝塞尔路径
- 剪辑到确定的贝塞尔路径
- 使用剪辑绘制用户笔画
- 在给定的透明线图上绘制
快速演示
这是一个简短的演示,展示了当用户使用所描述的绘图顺序开始在剪切的 Bézier 路径中绘图时的样子(另请参见下面的代码 sn-ps):
代码片段
贝塞尔路径示例
bezierPath = UIBezierPath()
bezierPath.move(to: CGPoint(x: 55.94, y: 60.19))
bezierPath.addCurve(to: CGPoint(x: 50.32, y: 94.09), controlPoint1: CGPoint(x: 56.92, y: 59.69), controlPoint2: CGPoint(x: 55.25, y: 73.99))
bezierPath.addCurve(to: CGPoint(x: 48.81, y: 115.93), controlPoint1: CGPoint(x: 46.9, y: 107.97), controlPoint2: CGPoint(x: 49.09, y: 115.33))
bezierPath.addCurve(to: CGPoint(x: 74.36, y: 146.45), controlPoint1: CGPoint(x: 50.56, y: 127.4), controlPoint2: CGPoint(x: 60.85, y: 141.06))
bezierPath.addCurve(to: CGPoint(x: 119.11, y: 126.29), controlPoint1: CGPoint(x: 93.52, y: 141.34), controlPoint2: CGPoint(x: 107.61, y: 134.31))
bezierPath.addCurve(to: CGPoint(x: 223.27, y: 93.88), controlPoint1: CGPoint(x: 150.33, y: 112.49), controlPoint2: CGPoint(x: 183.59, y: 100.44))
bezierPath.addCurve(to: CGPoint(x: 300.41, y: 69.01), controlPoint1: CGPoint(x: 250.68, y: 87.71), controlPoint2: CGPoint(x: 276.22, y: 79.2))
bezierPath.addCurve(to: CGPoint(x: 297.23, y: 59.69), controlPoint1: CGPoint(x: 301.38, y: 65.82), controlPoint2: CGPoint(x: 300.22, y: 62.01))
bezierPath.addCurve(to: CGPoint(x: 212.85, y: 38.3), controlPoint1: CGPoint(x: 290.2, y: 62.67), controlPoint2: CGPoint(x: 256.59, y: 52.37))
bezierPath.addCurve(to: CGPoint(x: 137.05, y: 37.2), controlPoint1: CGPoint(x: 191.43, y: 31.36), controlPoint2: CGPoint(x: 158.26, y: 29.92))
bezierPath.addCurve(to: CGPoint(x: 100.74, y: 48.08), controlPoint1: CGPoint(x: 126.18, y: 40.93), controlPoint2: CGPoint(x: 111.78, y: 44.75))
bezierPath.addCurve(to: CGPoint(x: 55.94, y: 60.19), controlPoint1: CGPoint(x: 86.15, y: 52.48), controlPoint2: CGPoint(x: 70.56, y: 56.69))
bezierPath.close()
剪辑到路径
self.currentBezierPath.addClip()
确定触摸是否在封闭的贝塞尔路径内开始
假设 self 是一个自定义视图,可以这样写:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
...
let point = touch.location(in: self)
...
let inside = bezierPath.contains(point)
...
绘制透明图
首先必须使绘图的背景透明。然后可以以支持透明度的格式存储图形,例如.png。
context.saveGState()
context.scaleBy(x: 1, y: -1)
context.translateBy(x: 0, y: -oOV7Impng.size.height)
context.draw(oOV7Impng.cgImage!, in: CGRect(x: 0, y: 0, width: oOV7Impng.size.width, height: oOV7Impng.size.height))
context.restoreGState()
如果应用中有很多绘图,可以考虑通过编程使图像的背景透明(例如,通过使白色像素透明)。取决于用例。