iOS Swift中UIView遮罩效果不符预期,如何实现目标遮罩?
如何用两个UIView实现目标遮罩效果?
背景
我尝试用以下代码通过两个UIView创建遮罩,遮罩功能已生效,但效果不符合预期。我想要实现图片中A所示的遮罩效果,实际得到的却是B的效果。
问题
如何通过两个UIView实现图片A那样的遮罩效果?
现有代码
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let redView = UIView(frame: CGRect(x: 100, y: 100, width: 200, height: 200)) redView.backgroundColor = .red view.addSubview(redView) let maskView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200)) maskView.backgroundColor = .blue maskView.layer.cornerRadius = 100 redView.mask = maskView } }
效果对比图

解决方案
要实现图片A的遮罩效果,核心是利用UIView作为mask时,不透明区域显示被遮罩视图,透明区域隐藏的特性。你当前的代码是让maskView本身为圆形不透明,所以redView只显示圆形部分;而要实现中间圆形显示、周围被遮罩的效果,需要让maskView的中间区域透明,周围不透明。
方法一:通过图层混合模式实现
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let redView = UIView(frame: CGRect(x: 100, y: 100, width: 200, height: 200)) redView.backgroundColor = .red view.addSubview(redView) // 创建遮罩容器视图,尺寸与redView一致 let maskContainer = UIView(frame: redView.bounds) // 容器背景设为不透明(颜色不影响,只要不透明即可) maskContainer.backgroundColor = .black // 创建中间圆形视图,作为要显示的透明区域 let circleView = UIView(frame: CGRect(x: 50, y: 50, width: 100, height: 100)) circleView.layer.cornerRadius = 50 circleView.backgroundColor = .clear maskContainer.addSubview(circleView) // 关键:用混合模式将圆形区域从容器中挖去 circleView.layer.compositingFilter = "destinationOut" // 设置遮罩 redView.mask = maskContainer } }
方法二:通过CAShapeLayer组合路径实现
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let redView = UIView(frame: CGRect(x: 100, y: 100, width: 200, height: 200)) redView.backgroundColor = .red view.addSubview(redView) // 创建外层遮罩视图,尺寸与redView一致 let outerMask = UIView(frame: redView.bounds) outerMask.backgroundColor = .black // 创建中间圆形区域的路径 let maskLayer = CAShapeLayer() // 先绘制全屏矩形路径 let fullPath = UIBezierPath(rect: outerMask.bounds) // 再绘制中间圆形路径,并从矩形中减去 let circlePath = UIBezierPath(ovalIn: CGRect(x: 50, y: 50, width: 100, height: 100)) fullPath.append(circlePath) fullPath.usesEvenOddFillRule = true maskLayer.path = fullPath.cgPath maskLayer.fillRule = .evenOdd // 将组合路径设为外层视图的遮罩 outerMask.layer.mask = maskLayer // 设置redView的遮罩 redView.mask = outerMask } }
两种方法都能实现图片A的效果:redView仅中间圆形区域显示,周围被遮罩隐藏。
内容的提问来源于stack exchange,提问作者user4806509
相关产品推荐
相关产品推荐

