【问题标题】:How to add a shadow to a view that's masked with a path如何向使用路径遮罩的视图添加阴影
【发布时间】:2025-11-24 09:15:01
【问题描述】:

如何向使用路径遮罩的视图添加阴影?

layer 有一个掩码属性,您可以像这样设置yourCustomView.layer.mask = somePath。但是如何添加一个也被 layer.mask 屏蔽的阴影?

【问题讨论】:

  • 抱歉,我不知道如何在此处进行问答类型的回答。它在标题中……但我会把它添加到正文中。

标签: ios swift uibezierpath


【解决方案1】:

我看到这个问题问了很多,答案到处都是,所以我想我会集中一点。

基本上,当您想为使用路径遮罩的视图添加阴影时,事情会变得很有趣。

这是我构建的一个扩展,它可以处理所有这些并且非常易于使用。 corners 参数是为基本圆角设置设置的,但您可以将其替换为您想要的任何 UIBezierPath。

import UIKit

public extension UIView {
    /// You will probably need to call this from viewDidLayoutSubviews()
    func roundCorners(corners: UIRectCorner = .bottomRight, radius: CGFloat = 40) {
        layoutIfNeeded()

        let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
        let mask = CAShapeLayer()
        mask.path = path.cgPath
        self.layer.mask = mask
    }

    /// You will probably need to call this from viewDidLayoutSubviews()
    func roundCornersWithShadow(corners: UIRectCorner = .bottomRight, cornerRadius radius: Double = 40, shadowOpacity: Float = 0.5, shadowRadius: Double = 4, shadowOffset: CGSize = CGSize(width: 0, height: 2), shadowColor: UIColor = .black, maskName: String = "mask", shadowName: String = "shadow") {

        layoutIfNeeded()

        let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius)).cgPath

        let maskLayer = CAShapeLayer()
        maskLayer.frame = bounds
        maskLayer.path = path
        layer.mask = maskLayer
        layer.name = maskName

        if let subLayers = superview?.layer.sublayers {
            for layer in subLayers where layer.name == shadowName { layer.removeFromSuperlayer() }
        }

        let shadowLayer = CAShapeLayer()
        shadowLayer.name = shadowName
        shadowLayer.path = path
        shadowLayer.frame = frame

        shadowLayer.shadowOpacity = shadowOpacity
        shadowLayer.shadowRadius = CGFloat(shadowRadius)
        shadowLayer.shadowColor = shadowColor.cgColor
        shadowLayer.shadowOffset = shadowOffset

        superview?.layer.insertSublayer(shadowLayer, below: layer)
    }
}

然后像这样使用它:

override func viewDidLayoutSubviews() {
    ...
    yourView.roundCornersWithShadow(corners: [.bottomRight, .bottomLeft, .topRight, .topLeft]) // Use whatever corners you want.
}

【讨论】: