如何将UIView作为另一个UIView的反向遮罩?
实现任意UIView作为反向遮罩的可行方案
要实现用任意UIView作为反向遮罩(即目标视图仅在遮罩视图的不可见区域显示),有两种实用方案,分别适配动态和静态场景:
方案1:基于图层混合模式(动态实时更新)
这种方案利用Core Animation的混合模式,直接通过视图层级实现反向遮罩,支持遮罩视图的动态变化(比如动画、子视图更新),无需手动刷新。
代码示例
// 1. 创建目标视图(示例为红色矩形) let targetView = UIView(frame: CGRect(x: 40, y: 40, width: 200, height: 200)) targetView.backgroundColor = .red view.addSubview(targetView) // 2. 创建任意遮罩视图(示例为带圆角的绿色圆形,可替换为任何UIView) let maskView = UIView(frame: CGRect(x: 90, y: 90, width: 100, height: 100)) maskView.backgroundColor = .green maskView.layer.cornerRadius = 50 // 3. 创建容器视图,将目标视图和遮罩视图放入其中 let containerView = UIView(frame: targetView.frame) containerView.addSubview(targetView) containerView.addSubview(maskView) view.addSubview(containerView) // 4. 设置混合模式,实现反向遮罩 maskView.layer.compositingFilter = "destinationOut" // 必须关闭组透明度,避免出现异常黑色背景 containerView.layer.allowsGroupOpacity = false
原理说明
destinationOut混合模式会让遮罩视图所在区域的目标视图内容被清除(镂空),保留遮罩视图以外的区域。- 关闭
allowsGroupOpacity是为了防止容器视图的透明度设置干扰混合效果,确保镂空区域完全透明。
方案2:基于快照反向生成遮罩图层(静态场景)
如果遮罩视图是静态的(不会动态变化),可以将遮罩视图的快照转换为反向alpha通道的图片,再作为目标视图的mask图层使用。
代码示例
extension UIView { /// 给当前视图应用任意UIView作为反向遮罩 func applyReverseMask(_ maskView: UIView) { // 获取遮罩视图的实时快照 guard let snapshot = maskView.snapshotView(afterScreenUpdates: true) else { return } // 创建图片上下文,生成反向alpha的遮罩图片 UIGraphicsBeginImageContextWithOptions(maskView.bounds.size, false, UIScreen.main.scale) snapshot.draw(at: .zero) // 反转alpha通道:清除原遮罩可见区域的alpha if let context = UIGraphicsGetCurrentContext() { context.setBlendMode(.destinationOut) UIRectFill(maskView.bounds) } let reversedMaskImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() // 创建遮罩图层并应用到目标视图 let maskLayer = CALayer() maskLayer.contents = reversedMaskImage?.cgImage maskLayer.frame = self.bounds self.layer.mask = maskLayer } } // 使用示例 targetView.applyReverseMask(maskView)
原理说明
- 通过
snapshotView获取遮罩视图的视觉快照,然后在图片上下文中用destinationOut混合模式清除原遮罩的可见区域,生成反向alpha的图片。 - 将该图片作为目标视图的
layer.mask,即可实现反向遮罩效果。
内容的提问来源于stack exchange,提问作者Andrei Herford
相关产品推荐
相关产品推荐

