在CGMutablePath中添加多个排除路径

问题描述 投票:0回答:2

我正在关注为winding rules documentation财产提供的fillRule,该财产用于试图识别该地区内部的一个点或不是。我的问题是尝试在路径中添加多个路径排除,如下所示。我试图在操场上调试它,但无法确定它是如何工作的以及实现结果所需的。当我在同一行中添加多个弧时会出现问题。

结果很有趣:

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

ios swift core-graphics calayer
2个回答
1
投票

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

要理解的主要是路径可以包含多个子路径。每个子路径可以关闭(它在它开始的地方结束)或打开(它在与它开始的不同点结束)。在子路径中,所有线段都已连接。

你想要实现的目标需要几个封闭的子路径。否则你无法获得断开连接的形状。

在你的一个例子中,显而易见的是,三个圆圈已经通过线自动连接,从而形成了一个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

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个矩形重叠子路径组成。在有一个子路径重叠的情况下,路径将不会被填充(偶数奇数填充规则,2个路径重叠)。然而,路径和两个子路径与填充颜色重叠的区域是可见的(3路径重叠)。

© www.soinside.com 2019 - 2024. All rights reserved.