我正在关注为winding rules documentation财产提供的fillRule
,该财产用于试图识别该地区内部的一个点或不是。我的问题是尝试在路径中添加多个路径排除,如下所示。我试图在操场上调试它,但无法确定它是如何工作的以及实现结果所需的。当我在同一行中添加多个弧时会出现问题。
结果很有趣:
let maskView = UIView(frame: UIScreen.main.bounds)
view.addSubview(maskView)
maskView.backgroundColor = UIColor.black.withAlphaComponent(0.7)
//
let path = CGMutablePath()
path.addArc(center: CGPoint(x: 20, y: 20),
radius: 10,
startAngle: 0, endAngle: 2 * .pi,
clockwise: false)
path.addArc(center: CGPoint(x: 220, y: 20),
radius: 10,
startAngle: 0, endAngle: 2 * .pi,
clockwise: false)
path.addArc(center: CGPoint(x: 100, y: 300),
radius: 12,
startAngle: 0, endAngle: 2 * .pi,
clockwise: false)
path.addRect(CGRect(origin: .zero, size: UIScreen.main.bounds.size))
let maskLayer = CAShapeLayer()
maskLayer.backgroundColor = UIColor.black.cgColor
maskLayer.path = path
maskLayer.fillRule = .evenOdd
maskView.layer.mask = maskLayer
Apple提供的代码在这里很容易实现:Flower pattern
你没有描述你真正想要实现的目标。我假设你想要一个有三个圆孔的矩形。
要理解的主要是路径可以包含多个子路径。每个子路径可以关闭(它在它开始的地方结束)或打开(它在与它开始的不同点结束)。在子路径中,所有线段都已连接。
你想要实现的目标需要几个封闭的子路径。否则你无法获得断开连接的形状。
在你的一个例子中,显而易见的是,三个圆圈已经通过线自动连接,从而形成了一个trinagle。 documation of addArc
提到这个:
如果路径已包含子路径,则此方法添加一条将当前点连接到弧的起始点的线。
要创建新的子路径,请移动到下一个子路径的开头(使用move
)或关闭前一个子路径(使用closeSubpath
)。所以代码的中间部分应如下所示:
let path = CGMutablePath()
path.addRect(CGRect(origin: .zero, size: UIScreen.main.bounds.size))
path.closeSubpath
path.addArc(center: CGPoint(x: 20, y: 20),
radius: 10,
startAngle: 0, endAngle: 2 * .pi,
clockwise: false)
path.closeSubpath
path.addArc(center: CGPoint(x: 220, y: 20),
radius: 10,
startAngle: 0, endAngle: 2 * .pi,
clockwise: false)
path.closeSubpath
path.addArc(center: CGPoint(x: 100, y: 300),
radius: 12,
startAngle: 0, endAngle: 2 * .pi,
clockwise: false)
path.closeSubpath
在您的示例中,您只设置了一个路径。但是,为了看到有效的fillRule
,您需要多个子路径。尝试执行以下操作:
CGMutablePath.addPath
)。maskLayer
中的路径有关工作示例,请参阅以下操场代码:
import UIKit
import PlaygroundSupport
class MaskView: UIView {
override static var layerClass: AnyClass {
return CAShapeLayer.self
}
var highlightedAreas = [CGPath]() {
didSet {
setNeedsLayout()
}
}
func setMaskColor(_ color: UIColor) {
(layer as? CAShapeLayer)?.fillColor = color.cgColor
(layer as? CAShapeLayer)?.fillRule = CAShapeLayerFillRule.evenOdd
}
override func layoutSubviews() {
super.layoutSubviews()
frame = superview?.bounds ?? .zero
let path = makePath()
(layer as? CAShapeLayer)?.path = path
}
private func makePath() -> CGPath {
let path = CGMutablePath()
path.addRect(bounds)
for subPath in highlightedAreas {
path.addPath(subPath)
}
return path
}
}
class DemoViewController: UIViewController {
private var mask: MaskView!
override func viewDidLoad() {
super.viewDidLoad()
mask = MaskView()
mask.backgroundColor = .clear
view.addSubview(mask)
mask.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
mask.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
mask.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
mask.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
view.backgroundColor = .green
let path1 = CGMutablePath()
path1.addRect(CGRect(x: 50, y: 50, width: 120, height: 80))
let path2 = CGMutablePath()
path2.addRect(CGRect(x: 150, y: 110, width: 80, height: 120))
mask.highlightedAreas = [path1, path2]
mask.setMaskColor(UIColor(white: 0, alpha: 0.7))
}
}
let demoController = DemoViewController()
demoController.preferredContentSize = CGSize(width: 300, height: 300)
PlaygroundPage.current.liveView = demoController
它会产生如下视图:
背景以绿色。深色是路径的填充颜色。该路径由视图大小的大矩形和2个矩形重叠子路径组成。在有一个子路径重叠的情况下,路径将不会被填充(偶数奇数填充规则,2个路径重叠)。然而,路径和两个子路径与填充颜色重叠的区域是可见的(3路径重叠)。