如何对同一视图多次使用 CAShapeLayer() 上的 UIBezierPath() swift 5

How to use UIBezierPath() on CAShapeLayer() multiple times for same view swift 5

我想使用 UIBezierPath()CAShapeLayer() 在我的 table 视图单元格中切断容器视图的上部和下部。代码如下:

func cutView() {
        let containerViewHeight: CGFloat = containerView.frame.height
        let headerCut: CGFloat = 50
        let newHeight = containerViewHeight - headerCut/2
        let newHeaderUpperLayer = CAShapeLayer()
        let newHeaderLowerLayer = CAShapeLayer()

        newHeaderUpperLayer.fillColor = UIColor.black.cgColor
        newHeaderLowerLayer.fillColor = UIColor.black.cgColor
        containerView.layer.mask = newHeaderUpperLayer
        containerView.layer.mask = newHeaderLowerLayer

        let getViewFrame = CGRect(x: 0, y: -newHeight, width: containerView.bounds.width, height: containerViewHeight)
        let cutDirectionUpper = UIBezierPath()
        let cutDirectionLower = UIBezierPath()

        cutDirectionUpper.move(to: CGPoint(x: 0, y: 0))
        cutDirectionUpper.addLine(to: CGPoint(x: getViewFrame.width, y: headerCut))
        cutDirectionUpper.addLine(to: CGPoint(x: getViewFrame.width, y: getViewFrame.height))
        cutDirectionUpper.addLine(to: CGPoint(x: 0, y: getViewFrame.height))

        cutDirectionLower.move(to: CGPoint(x: 0, y: 0))
        cutDirectionLower.addLine(to: CGPoint(x: getViewFrame.width, y: 0))
        cutDirectionLower.addLine(to: CGPoint(x: getViewFrame.width, y: getViewFrame.height))
        cutDirectionLower.addLine(to: CGPoint(x: 0, y: getViewFrame.height - headerCut))

        newHeaderUpperLayer.path = cutDirectionUpper.cgPath
        newHeaderLowerLayer.path = cutDirectionLower.cgPath
    }

它是分开工作的,但不是一起工作的。我在这里缺少什么?任何建议将不胜感激。提前致谢。

如果我单独运行它,效果是这样的:

但我想要的是:

使用组合 UIBezierPath():

func cutView() {
        let containerViewHeight: CGFloat = containerView.frame.height
        let headerCut: CGFloat = 50
        let newHeight = containerViewHeight - headerCut/2
        let newHeaderLayer = CAShapeLayer()

        newHeaderLayer.fillColor = UIColor.black.cgColor
        containerView.layer.mask = newHeaderLayer

        let getViewFrame = CGRect(x: 0, y: -newHeight, width: containerView.bounds.width, height: containerViewHeight)
        let cutDirectionLower = UIBezierPath()
        let cutDirectionUpper = UIBezierPath()

        cutDirectionUpper.move(to: CGPoint(x: 0, y: 0))
        cutDirectionUpper.addLine(to: CGPoint(x: getViewFrame.width, y: headerCut))
        cutDirectionUpper.addLine(to: CGPoint(x: getViewFrame.width, y: getViewFrame.height))
        cutDirectionUpper.addLine(to: CGPoint(x: 0, y: getViewFrame.height))

        cutDirectionLower.move(to: CGPoint(x: 0, y: 0))
        cutDirectionLower.addLine(to: CGPoint(x: getViewFrame.width, y: 0))
        cutDirectionLower.addLine(to: CGPoint(x: getViewFrame.width, y: getViewFrame.height))
        cutDirectionLower.addLine(to: CGPoint(x: 0, y: getViewFrame.height - headerCut))

        cutDirectionUpper.append(cutDirectionLower)
        newHeaderLayer.path = cutDirectionUpper.cgPath
    }

使用组合 CGMutablePath():

func cutView() {
        let containerViewHeight: CGFloat = containerView.frame.height
        let headerCut: CGFloat = 50
        let newHeight = containerViewHeight - headerCut/2
        let newHeaderLayer = CAShapeLayer()
        let combinedPath = CGMutablePath()

        newHeaderLayer.fillColor = UIColor.black.cgColor
        containerView.layer.mask = newHeaderLayer

        let getViewFrame = CGRect(x: 0, y: -newHeight, width: containerView.bounds.width, height: containerViewHeight)
        let cutDirectionLower = UIBezierPath()
        let cutDirectionUpper = UIBezierPath()

        cutDirectionUpper.move(to: CGPoint(x: 0, y: 0))
        cutDirectionUpper.addLine(to: CGPoint(x: getViewFrame.width, y: headerCut))
        cutDirectionUpper.addLine(to: CGPoint(x: getViewFrame.width, y: getViewFrame.height))
        cutDirectionUpper.addLine(to: CGPoint(x: 0, y: getViewFrame.height))

        cutDirectionLower.move(to: CGPoint(x: 0, y: 0))
        cutDirectionLower.addLine(to: CGPoint(x: getViewFrame.width, y: 0))
        cutDirectionLower.addLine(to: CGPoint(x: getViewFrame.width, y: getViewFrame.height))
        cutDirectionLower.addLine(to: CGPoint(x: 0, y: getViewFrame.height - headerCut))

        combinedPath.addPath(cutDirectionUpper.cgPath)
        combinedPath.addPath(cutDirectionLower.cgPath)

        newHeaderLayer.path = combinedPath
    }

他们俩都去掉了上下切。我在这里缺少什么?
分别使用combined CGMutablePath() & combined UIBezierPath()输出如下:

您正在将两个蒙版分配给同一层。显然它会接受最后一次赋值(就像任何其他变量一样)。

您可以执行以下操作。

  1. 有一个可变路径。
  2. 添加这两个路径并将它们存储在这个可变路径中。 (或附加在相同的可变路径中)。
  3. 有基于此路径的单一掩码。

我认为您会发现使用为您处理屏蔽的子类 UIImageView 会容易得多。

开始像这样定义你的形状:

您将 movept1addLinept2addLinept3addLinept4,然后 close 路径。

要使其自动运行,请在 layoutSubviews() 中更新子类中的路径——这样它会在视图更改大小时调整其大小。

这是我用来创建该图像的示例:

class CutImageView: UIImageView {

    let maskLayer = CAShapeLayer()

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }

    func commonInit() -> Void {
        layer.mask = maskLayer
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        let headerCut: CGFloat = 50

        let pt1: CGPoint = CGPoint(x: bounds.minX, y: bounds.maxY - headerCut)
        let pt2: CGPoint = CGPoint(x: bounds.minX, y: bounds.minY)
        let pt3: CGPoint = CGPoint(x: bounds.maxX, y: headerCut)
        let pt4: CGPoint = CGPoint(x: bounds.maxX, y: bounds.maxY)

        let pth = UIBezierPath()

        pth.move(to: pt1)
        pth.addLine(to: pt2)
        pth.addLine(to: pt3)
        pth.addLine(to: pt4)
        pth.close()

        maskLayer.path = pth.cgPath

    }

}

class ViewController: UIViewController {

    let cutImageView: CutImageView = {
        let v = CutImageView(frame: CGRect.zero)
        v.translatesAutoresizingMaskIntoConstraints = false
        v.contentMode = .scaleToFill
        return v
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        guard let bkgImage = UIImage(named: "background") else {
            fatalError("missing images")
        }

        view.backgroundColor = .systemGreen

        view.addSubview(cutImageView)

        let g = view.safeAreaLayoutGuide

        NSLayoutConstraint.activate([

            cutImageView.centerYAnchor.constraint(equalTo: g.centerYAnchor, constant: 0.0),
            cutImageView.centerXAnchor.constraint(equalTo: g.centerXAnchor, constant: 0.0),
            cutImageView.widthAnchor.constraint(equalToConstant: 300.0),
            cutImageView.heightAnchor.constraint(equalToConstant: 240.0),


        ])

        cutImageView.image = bkgImage

    }
}