在CGMutablePath中添加多个排除路径

时间:2019-04-16 10:55:26

标签: ios swift core-graphics calayer

我遵循为fillRule属性提供的winding rules documentation,该属性用于尝试识别某个点是否位于区域内。 我的问题是尝试在以下路径中添加多个路径排除项。我试图在操场上调试它,但无法确定它是如何工作的以及实现结果所需的条件。当我在同一行中添加多个弧时,就会出现问题。

结果很有趣:

enter image description here enter image description here

    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

2 个答案:

答案 0 :(得分:1)

您没有描述您真正想要实现的目标。我假设您想要一个带有三个圆孔的矩形。

主要要理解的是,路径可以包含多个 subpaths 。每个子路径可以 closed (在开始处结束)或 open (在与开始处不同的点处结束)。在子路径中,所有线段均已连接。

您要实现的目标需要几个封闭的子路径。否则,您将无法获得断开的形状。

在您的一个示例中,很明显三个圆圈已自动通过线连接起来,从而产生了琐碎的事情。 documation of addArc提到了这一点:

  

如果路径已经包含子路径,则此方法添加一行   将当前点连接到圆弧的起点。

要创建新的子路径,请移动到下一个子路径的开头(使用move)或 close 上一个子路径(使用{ {1}})。因此,代码的中间部分应如下所示:

closeSubpath

答案 1 :(得分:0)

在您的示例中,您仅设置了一条路径。但是,为了看到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

它产生的视图如下所示:

enter image description here

视图背景为绿色。深色是路径的填充色。 该路径包括一个与视图大小相同的大矩形和2个矩形的重叠子路径。如果有一条子路径重叠,则不会填充该路径(奇数填充规则,两条路径重叠)。但是,路径和两个子路径与填充颜色重叠的区域是可见的(3个路径重叠)。