如何对同一视图多次使用 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()
输出如下:
您正在将两个蒙版分配给同一层。显然它会接受最后一次赋值(就像任何其他变量一样)。
您可以执行以下操作。
- 有一个可变路径。
- 添加这两个路径并将它们存储在这个可变路径中。 (或附加在相同的可变路径中)。
- 有基于此路径的单一掩码。
我认为您会发现使用为您处理屏蔽的子类 UIImageView
会容易得多。
开始像这样定义你的形状:
您将 move
到 pt1
、addLine
到 pt2
、addLine
到 pt3
、addLine
到 pt4
,然后 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
}
}
我想使用 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()
输出如下:
您正在将两个蒙版分配给同一层。显然它会接受最后一次赋值(就像任何其他变量一样)。
您可以执行以下操作。
- 有一个可变路径。
- 添加这两个路径并将它们存储在这个可变路径中。 (或附加在相同的可变路径中)。
- 有基于此路径的单一掩码。
我认为您会发现使用为您处理屏蔽的子类 UIImageView
会容易得多。
开始像这样定义你的形状:
您将 move
到 pt1
、addLine
到 pt2
、addLine
到 pt3
、addLine
到 pt4
,然后 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
}
}