You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 18:54:04