如何将多个蒙版应用于UIView



我有一个关于如何将多个蒙版应用于已经有遮罩的UIView的问题。

情况:
我有一个带有活动蒙版的视图,该遮罩在其左上角创建了一个孔,这是一个模板 UIView,可以在项目中的任何地方重复使用。在项目的后期,我希望能够创建第二个孔,但这次是在右下角,这不需要创建一个全新的 UIView。

问题:
当我应用底部面罩时,它当然会替换第一个面罩,从而去除顶部孔......有没有办法将它们结合起来?就此而言,将任何现有的面具与新面具相结合?

提前谢谢你!

根据@Sharad的回答,我意识到重新添加视图的矩形将使我能够将原始和新蒙版合并为一个。

这是我的解决方案:

func cutCircle(inView view: UIView, withRect rect: CGRect) {
// Create new path and mask
let newMask = CAShapeLayer()
let newPath = UIBezierPath(ovalIn: rect)
// Create path to clip
let newClipPath = UIBezierPath(rect: view.bounds)
newClipPath.append(newPath)
// If view already has a mask
if let originalMask = view.layer.mask,
let originalShape = originalMask as? CAShapeLayer,
let originalPath = originalShape.path {
// Create bezierpath from original mask's path
let originalBezierPath = UIBezierPath(cgPath: originalPath)
// Append view's bounds to "reset" the mask path before we re-apply the original
newClipPath.append(UIBezierPath(rect: view.bounds))
// Combine new and original paths
newClipPath.append(originalBezierPath)
}
// Apply new mask
newMask.path = newClipPath.cgPath
newMask.fillRule = kCAFillRuleEvenOdd
view.layer.mask = newMask
}

这是我在UIView项目中用于创建一个圆形和一个矩形掩码的代码,您可以用相同的弧形代码替换UIBezierPath行:

func createCircleMask(view: UIView, x: CGFloat, y: CGFloat, radius: CGFloat, downloadRect: CGRect){
self.layer.sublayers?.forEach { ($0 as? CAShapeLayer)?.removeFromSuperlayer() }
let mutablePath      = CGMutablePath()
mutablePath.addArc(center: CGPoint(x: x, y: y + radius), radius: radius, startAngle: 0.0, endAngle: 2 * 3.14, clockwise: false)
mutablePath.addRect(view.bounds)
let path             = UIBezierPath(roundedRect: downloadRect, byRoundingCorners: [.topLeft, .bottomRight], cornerRadii: CGSize(width: 5, height: 5))
mutablePath.addPath(path.cgPath)
let mask             = CAShapeLayer()
mask.path            = mutablePath
mask.fillRule        = kCAFillRuleEvenOdd
mask.backgroundColor = UIColor.clear.cgColor

view.layer.mask      = mask
}

传递相同的 UIView,它会删除以前的图层并在相同的 UIView 上应用新的蒙版。

在这里mask.fillRule = kCAFillRuleEvenOdd很重要。如果您注意到有 3 个mutablePath.addPath()函数,kCAFillRuleEvenOdd的作用是,它首先创建一个带有圆弧的孔,然后添加该视图绑定的 Rect,然后添加另一个蒙版以创建第二个孔。

如果您不仅有"简单形状",而且有来自其他视图(如UILabelUIImageView(的实际图层,则可以执行以下操作。

let maskLayer = CALayer()
maskLayer.frame = viewToBeMasked.bounds
maskLayer.addSublayer(self.imageView.layer)
maskLayer.addSublayer(self.label.layer)
viewToBeMasked.layer.mask = maskLayer

所以基本上我只是创建一个 maskLayer,其中包含所有其他视图的图层作为子图层,然后将其用作遮罩。

最新更新