【问题标题】:How to use UIBezierPath() on CAShapeLayer() multiple times for same view swift 5如何在 CAShapeLayer() 上多次使用 UIBezierPath() 以获得相同的视图 swift 5
【发布时间】:2019-11-21 17:32:47
【问题描述】:

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

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
    }

它们都去除了上下切口。我在这里缺少什么?
分别使用组合CGMutablePath()和组合UIBezierPath()的输出如下:

【问题讨论】:

  • 你说的是containerView.layer.mask = newHeaderUpperLayer; containerView.layer.mask = newHeaderLowerLayer。所以你完全扔掉第一个蒙版层,用第二个替换它。
  • @matt 感谢您的评论。但我想在同一个containerView 上绘制它们。那我该怎么办?
  • 我已经尝试过结合CGMutablePath() 和结合UIBezierPath(),但它们都不起作用,我在这里缺少什么?
  • 为什么不直接使用两个形状图层作为单个蒙版图层的子图层?
  • containerView.layer.mask?.addSublayer(newHeaderUpperLayer) & containerView.layer.mask?.addSublayer(newHeaderLowerLayer) 相同的结果。 newHeaderUpperLayer.addSublayer(newHeaderLowerLayer) & containerView.layer.mask?.addSublayer(newHeaderUpperLayer) 相同的结果。两个切口都消失了。 :(

标签: ios swift uiview uibezierpath cashapelayer


【解决方案1】:

我认为您会发现使用为您处理掩码的子类 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

    }
}

【讨论】:

  • 男人,我不知道怎么说,但爱你。 :D 非常感谢分享这段很棒的代码。 O:) 我在浪费时间与该死的UIView
【解决方案2】:

您正在为同一图层分配两个蒙版。显然,它需要最后一次赋值(就像任何其他变量一样)。

这是你可以做的。

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

【讨论】:

  • 感谢您的建议。我正在调查。
  • 我已经尝试过结合CGMutablePath() 和结合UIBezierPath(),但是它们都没有工作,我在这里错过了什么?问题已使用代码更新。
猜你喜欢
  • 2016-12-05
  • 1970-01-01
  • 2017-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多