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

如何为带有圆角的UIView添加适配圆角的内阴影

我之前也被这个问题坑过!网上大部分内阴影方案都是给矩形加阴影,完全不管圆角,导致阴影和View的圆角边缘脱节,特别违和。下面给你两种能完美适配圆角的实现方式,亲测好用:

方法一:自定义View子类(推荐,可复用)

这种方式把内阴影逻辑封装在自定义View里,后续修改圆角、调整阴影参数都很方便,而且能自动适配布局变化。

class RoundedInnerShadowView: UIView {
    // 暴露圆角属性,修改时自动更新内阴影
    var innerCornerRadius: CGFloat = 16 {
        didSet {
            updateInnerShadow()
            layer.cornerRadius = innerCornerRadius
        }
    }
    
    private let innerShadowLayer = CAShapeLayer()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupInnerShadowConfig()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupInnerShadowConfig()
    }
    
    private func setupInnerShadowConfig() {
        // 核心:用evenOdd填充规则实现内阴影范围
        innerShadowLayer.fillRule = .evenOdd
        // 自定义阴影参数,可按需调整
        innerShadowLayer.shadowColor = UIColor.black.cgColor
        innerShadowLayer.shadowOffset = CGSize(width: 0, height: 2)
        innerShadowLayer.shadowOpacity = 0.3
        innerShadowLayer.shadowRadius = 4
        layer.addSublayer(innerShadowLayer)
        // 记得给View本身设圆角,不然View还是直角
        layer.cornerRadius = innerCornerRadius
        layer.masksToBounds = true
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        updateInnerShadow()
    }
    
    private func updateInnerShadow() {
        // 创建一个比View大的外部路径(避免阴影被裁剪)
        let outerPath = UIBezierPath(rect: bounds.insetBy(dx: -20, dy: -20))
        // 创建和View完全一致的圆角内部路径
        let innerPath = UIBezierPath(roundedRect: bounds, cornerRadius: innerCornerRadius)
        // 合并路径,evenOdd规则下,外部减内部的区域会被填充阴影
        outerPath.append(innerPath)
        
        innerShadowLayer.path = outerPath.cgPath
        innerShadowLayer.frame = bounds.insetBy(dx: -20, dy: -20)
    }
}

关键说明:

  • 用evenOdd填充规则,让阴影只出现在「外部大矩形 - 内部圆角矩形」的环形区域,完美贴合圆角边缘
  • 外部路径要比View大一些(这里用了-20的inset),保证阴影不会被View的masksToBounds裁剪
  • 重写layoutSubviews,确保布局变化时阴影能同步更新
方法二:UIView扩展(快速给已有View添加内阴影)

如果不想自定义View,也可以写个扩展方法,快速给任意UIView加上适配圆角的内阴影:

extension UIView {
    func addRoundedInnerShadow(cornerRadius: CGFloat,
                               shadowColor: UIColor = .black,
                               shadowOffset: CGSize = CGSize(width: 0, height: 2),
                               shadowOpacity: Float = 0.3,
                               shadowRadius: CGFloat = 4) {
        // 先给View本身设置圆角
        layer.cornerRadius = cornerRadius
        layer.masksToBounds = true
        
        let innerShadowLayer = CAShapeLayer()
        innerShadowLayer.fillRule = .evenOdd
        innerShadowLayer.shadowColor = shadowColor.cgColor
        innerShadowLayer.shadowOffset = shadowOffset
        innerShadowLayer.shadowOpacity = shadowOpacity
        innerShadowLayer.shadowRadius = shadowRadius
        
        let outerPath = UIBezierPath(rect: bounds.insetBy(dx: -shadowRadius*2, dy: -shadowRadius*2))
        let innerPath = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius)
        outerPath.append(innerPath)
        
        innerShadowLayer.path = outerPath.cgPath
        innerShadowLayer.frame = bounds.insetBy(dx: -shadowRadius*2, dy: -shadowRadius*2)
        layer.addSublayer(innerShadowLayer)
        
        // 注意:如果View后续尺寸变化,需要重新调用这个方法更新阴影,或者把layer保存下来在layoutSubviews里更新
    }
}

使用示例:

// 给一个已有的UIView添加内阴影
let myView = UIView(frame: CGRect(x: 50, y: 50, width: 200, height: 200))
myView.addRoundedInnerShadow(cornerRadius: 20)

额外提示:

  • 调整shadowOffset可以改变内阴影的方向(比如CGSize(width: -2, height: 0)就是左侧内阴影)
  • shadowOpacity控制阴影深浅,shadowRadius控制阴影模糊程度
  • 如果需要动态修改圆角或阴影参数,记得同步更新阴影Layer的路径

内容的提问来源于stack exchange,提问作者chnski

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 08:52:34