Swift - 在蒙版图像上放置阴影

Posted

技术标签:

【中文标题】Swift - 在蒙版图像上放置阴影【英文标题】:Swift - drop shadow on the masked image 【发布时间】:2021-09-15 13:54:13 【问题描述】:

我只是想给图像添加一个阴影,而不仅仅是矩形,我想应用与图像相同的蒙版效果。 关于堆栈溢出,我发现了同样的问题,但答案是在 Objective-c 语言中提出的 - ios SDK - drop shadow on masked image 你能帮我解决这个问题的快速代码吗? 提前致谢。

class drawView: UIView 
override func draw(_ rect: CGRect) 
    super.draw(rect)
    guard let context = UIGraphicsGetCurrentContext() else 
        return
    
    self.drawCircle(context)

private func drawCircle(_ context: CGContext)
    context.setStrokeColor(UIColor.black.cgColor)
    let newMask = CAShapeLayer()
    let circlePath = UIBezierPath(ovalIn: .init(x: 0, y: 0, width: 50, height: 50))
    circlePath.stroke()
    newMask.path = circlePath.cgPath
    self.layer.mask = newMask //if I apply this, then shadow disappears
    
    self.layer.shadowColor = UIColor.black.cgColor
    self.layer.shadowOpacity = 0.15
    self.layer.shadowOffset = .init(width: 10, height: -10)
    self.layer.shadowRadius = 2

【问题讨论】:

添加有问题的代码@LeoDabus 【参考方案1】:

有多种方法可以解决这个问题。

我建议使用带有UIImageView 子视图的自定义UIView

我们屏蔽imageView,然后将图层阴影应用到自定义视图本身:

class ShadowMaskImageView: UIView 
    
    let theImageView = UIImageView()
    let maskShape = CAShapeLayer()

    var image: UIImage = UIImage() 
        didSet 
            theImageView.image = image
        
    
    
    override init(frame: CGRect) 
        super.init(frame: frame)
        commonInit()
    
    required init?(coder: NSCoder) 
        super.init(coder: coder)
        commonInit()
    
    func commonInit() -> Void 
        theImageView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(theImageView)
        NSLayoutConstraint.activate([
            theImageView.topAnchor.constraint(equalTo: topAnchor),
            theImageView.leadingAnchor.constraint(equalTo: leadingAnchor),
            theImageView.trailingAnchor.constraint(equalTo: trailingAnchor),
            theImageView.bottomAnchor.constraint(equalTo: bottomAnchor),
        ])

        theImageView.layer.mask = maskShape

        layer.shadowOffset = CGSize(width: 10.0, height: -10.0)
        layer.shadowColor = UIColor.black.cgColor
        layer.shadowRadius = 2
        layer.shadowOpacity = 0.15
        
    
    
    override func layoutSubviews() 
        super.layoutSubviews()

        maskShape.frame = bounds

        // let's inset the image frame by 10-pts on all sides
        //  so our 10 x -10 shadow will fit inside the bounds
        let r = bounds.insetBy(dx: 10.0, dy: 10.0)
        
        // oval path
        let pth = UIBezierPath(ovalIn: r)
        maskShape.path = pth.cgPath
        
    
    

这是它的外观(红色轮廓矩形只是显示视图框架)...

首先,没有遮罩或阴影:

现在,只有面具:

并且,使用蒙版和阴影:

最后,没有显示框架的红色边框:

这是一个示例视图控制器:

class MaskShadowViewController: UIViewController 
    
    let testView = ShadowMaskImageView()
    
    override func viewDidLoad() 
        super.viewDidLoad()
        
        // make sure we can load the image
        guard let img = UIImage(named: "sample") else 
            fatalError("Could not load sample image!!!")
        
        
        // set the image
        testView.image = img

        // add testView and set its height equal to the ratio of the original image
        testView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(testView)
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            testView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            testView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            testView.heightAnchor.constraint(equalTo: testView.widthAnchor, multiplier: img.size.height / img.size.width),
            testView.centerYAnchor.constraint(equalTo: g.centerYAnchor),
        ])

        // un-comment the following if we want to see the frame of our custom view

        //let frameView = UIView()
        //frameView.translatesAutoresizingMaskIntoConstraints = false
        //view.addSubview(frameView)
        //NSLayoutConstraint.activate([
        //  frameView.topAnchor.constraint(equalTo: testView.topAnchor, constant: 0.0),
        //  frameView.leadingAnchor.constraint(equalTo: testView.leadingAnchor, constant: 0.0),
        //  frameView.trailingAnchor.constraint(equalTo: testView.trailingAnchor, constant: 0.0),
        //  frameView.bottomAnchor.constraint(equalTo: testView.bottomAnchor, constant: 0.0),
        //])
        //
        //frameView.layer.borderWidth = 1
        //frameView.layer.borderColor = UIColor.red.cgColor

    
    

【讨论】:

以上是关于Swift - 在蒙版图像上放置阴影的主要内容,如果未能解决你的问题,请参考以下文章

在 Swift 中的 UITextView 上放置阴影

java Android - Picasso的alpha / shadow变换(这允许您在源图像上绘制透明的黑色阴影)

java Android - Picasso的alpha / shadow变换(这允许您在源图像上绘制透明的黑色阴影)

java Android - Picasso的alpha / shadow变换(这允许您在源图像上绘制透明的黑色阴影)

java Android - Picasso的alpha / shadow变换(这允许您在源图像上绘制透明的黑色阴影)

java Android - Picasso的alpha / shadow变换(这允许您在源图像上绘制透明的黑色阴影)