如何为带有圆角的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
相关产品推荐
相关产品推荐

