Swift如何为已设置蒙版的视图添加与蒙版形状一致的投影效果
问题原因
layer.mask的作用是裁剪视图图层的所有可见内容,阴影属于蒙版外的渲染部分,自然会被一起裁剪掉,所以要实现带蒙版形状的阴影需要拆成两个图层处理:一个带蒙版负责裁剪内容,另一个同级图层专门负责渲染和蒙版形状一致的阴影。
正确Swift实现方案
class DrawView: UIView { // 专门承载阴影的图层 private let shadowLayer = CAShapeLayer() // 蒙版图层 private let maskLayer = CAShapeLayer() // 统一的形状路径,保持阴影和蒙版形状完全一致 private let circlePath = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 50, height: 50)) override init(frame: CGRect) { super.init(frame: frame) setupLayers() } required init?(coder: NSCoder) { super.init(coder: coder) setupLayers() } private func setupLayers() { // 配置阴影图层 shadowLayer.path = circlePath.cgPath shadowLayer.shadowColor = UIColor.black.cgColor shadowLayer.shadowOpacity = 0.15 shadowLayer.shadowOffset = CGSize(width: 10, height: -10) shadowLayer.shadowRadius = 2 // 阴影图层不需要填充内容,仅保留阴影渲染 shadowLayer.fillColor = UIColor.clear.cgColor layer.insertSublayer(shadowLayer, at: 0) // 配置蒙版,用来裁剪当前视图的所有展示内容 maskLayer.path = circlePath.cgPath layer.mask = maskLayer } override func draw(_ rect: CGRect) { super.draw(rect) guard let context = UIGraphicsGetCurrentContext() else { return } // 绘制自定义内容,会被maskLayer自动裁剪为对应形状 context.setStrokeColor(UIColor.black.cgColor) circlePath.stroke() } }
注意事项
- 如果形状需要跟随视图尺寸动态变化,只要在
layoutSubviews中同步更新circlePath、shadowLayer.path、maskLayer.path三个属性即可,不需要重复创建图层 - 不要在
draw(_:)方法中频繁创建、修改layer属性,该方法每次视图重绘都会触发,反复操作会产生不必要的性能消耗 - 方案支持任意自定义贝塞尔路径,不局限于圆形,只要保证阴影图层和蒙版图层的路径完全一致即可
内容的提问来源于stack exchange,提问作者dsplatonov
相关产品推荐
相关产品推荐

