首页 > 解决方案 > Swift - 在蒙版图像上放置阴影

问题描述

我只是想给图像添加一个阴影,这不仅仅是矩形,我想应用与图像相同的蒙版效果。在堆栈溢出时,我发现了同样的问题,但答案是在 Objective-C 语言 - iOS SDK - 蒙面图像上的阴影上提出的, 你能帮我解决这个问题的 swift-code 吗?提前致谢。

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
}

}

标签: swiftuiimageview

解决方案


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

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

我们屏蔽 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

    }
    
}

推荐阅读