假设我们有两个UIBezierPaths,分别是path1和path2 ...(它们是在运行时相对于视图边界定义的,并且已经作为同一视图的属性存在)。
我们要获取类型为UIBezierPath的新路径path3,这是从path1中减去path2的结果:
完成此操作的方式(如here所示)是
path1.append(path2.reversing())
但是,这似乎仅在path1完全包含path2的情况下有效。
例如,考虑只有部分相交的情况-path1不完全包含path2。如果我们采用与上述相同的方法,则会发生这种情况:
在Android中,答案是:
path1.op(path2, Path.Op.DIFFERENCE);
那么... IOS中是否有等效的简单操作?
如果没有,是否存在可以写为的函数:
func returnPath2CutOutOfPath1(path1: UIBezierPath, path2: UiBezierPath) -> UIBezierPath {
// the mystery lies within these here parts. :)
}
答案 0 :(得分:2)
我已经实现了所需的解决方案,但是我已经为200x200尺寸的静态视图创建了代码。
让我告诉您我尝试过的事情,并告诉我对您有多有用。
首先,我创建了自定义视图类,在其中编写了绘制视图的代码。请参见以下代码:
class MyCustomView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
func setup() {
// Create a CAShapeLayer
let shapeLayer = CAShapeLayer()
let path1 = self.path1()
let path2 = self.path2()
// Append path2 to path1
path1.append(path2.reversing())
// Set true of Even Odd Fill Rule
path1.usesEvenOddFillRule = true
// Call this method to add clip in path
path1.addClip()
shapeLayer.path = path1.cgPath
// Apply other properties related to the path
shapeLayer.strokeColor = UIColor.blue.cgColor
shapeLayer.fillColor = UIColor.black.cgColor
shapeLayer.lineWidth = 1.0
shapeLayer.position = CGPoint(x: 0, y: 0)
// Add the new layer to our custom view
self.layer.addSublayer(shapeLayer)
}
//-----------------------------------------------------
// This is static code as I have already told you first.
// Create First UIBezierPath,
func path1() -> UIBezierPath {
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: 0, y: 200))
path.addLine(to: CGPoint(x: 200, y: 200))
path.addLine(to: CGPoint(x: 200, y: 0))
path.close()
return path
}
// Create Second UIBezierPath
func path2() -> UIBezierPath {
let path = UIBezierPath()
path.move(to: CGPoint(x: 50, y: -50))
path.addLine(to: CGPoint(x: 50, y: 150))
path.addLine(to: CGPoint(x: 250, y: 150))
path.addLine(to: CGPoint(x: 250, y: -50))
path.close()
return path
}
}
此自定义类代码将根据您的实际结果创建共享层,如图4所示。
现在要使用此类,我已经创建了具有固定高度和宽度的上述类的实例。
override func viewDidLoad() {
super.viewDidLoad()
// Create a new UIView and add it to the view controller
let myView = MyCustomView()
// Must set clipsToBounds true to remove extra layer which are display out side of view as like your **actual** result in figure 4.
myView.clipsToBounds = true
myView.frame = CGRect(x: 50, y: 100, width: 200, height: 200)
myView.backgroundColor = UIColor.orange
view.addSubview(myView)
}
这将显示如下视图,这是您想要的结果。
答案 1 :(得分:1)
没有直接的方法可以将UIBezierPaths的差异作为iOS上的新路径。
测试用例
private func path2() -> UIBezierPath {
return UIBezierPath(rect: CGRect(x: 100, y: 50, width: 200, height: 200))
}
private func path1() -> UIBezierPath {
return UIBezierPath(rect: CGRect(x: 50, y: 100, width: 200, height: 200))
}
起点:仅显示哪个路径代表什么:路径1为黄色,路径2为绿色:
可能性1
您可能已经看到了这种可能性:在问题中提到的链接中,如果只需要执行填充操作,还有一个聪明的解决方案。
代码是从此答案中提取的(来自您发布的链接)https://stackoverflow.com/a/8860341-仅转换为Swift:
func fillDifference(path2: UIBezierPath, path1: UIBezierPath) {
let clipPath = UIBezierPath.init(rect: .infinite)
clipPath.append(path2)
clipPath.usesEvenOddFillRule = true
UIGraphicsGetCurrentContext()?.saveGState()
clipPath.addClip()
path1.fill()
UIGraphicsGetCurrentContext()?.restoreGState()
}
因此,这将填充路径,但不会返回UIBezierPath,这意味着您不能应用轮廓,背景,轮廓宽度等,因为结果不是UIBezierPath。
它看起来像这样:
可能性2
您可以使用第三方库,例如一位来自名为亚当·沃夫(Adam Wulf)的作者在这里:https://github.com/adamwulf/ClippingBezier。
该库是用Objective-C编写的,但是可以从Swift调用。
在Swift中,它看起来像这样:
override func draw(_ rect: CGRect) {
let result = self.path1().difference(with: self.path2())
for p in result ?? [] {
p.stroke()
}
}
如果要使用此库,则必须注意一个小提示:如自述文件所述,在项目设置的“其他链接器标志”中,必须添加“ -ObjC ++ -lstdc ++”,否则将在没有投诉,但由于没有找到UIBEzierPath类别,因此将无提示地不加载框架并最终崩溃。
结果如下:
因此,这实际上将提供您想要的结果,但是您将必须使用第3方库。