如何在 UIVisualEffectView 中打一个透明孔?

How to make a transparent hole in UIVisualEffectView?

我有一个简单的 UIViewController,其中 UIVisualEffectView 使用 overCurrentContext 在另一个控制器上显示。

还好。

现在我尝试通过以下方式在该视图中打一个洞:

class CoverView: UIView {
    private let blurView: UIVisualEffectView = {
        UIVisualEffectView(effect: UIBlurEffect(style: .dark))
    }()

    // MARK: - Internal

    func setup() {
        addSubview(blurView)
        blurView.snp.makeConstraints { maker in
            maker.edges.equalToSuperview()
        }
        blurView.makeClearHole(rect: CGRect(x: 100, y: 100, width: 100, height: 230))
    }
}

extension UIView {
    func makeClearHole(rect: CGRect) {
        let maskLayer = CAShapeLayer()
        maskLayer.fillRule = CAShapeLayerFillRule.evenOdd
        maskLayer.fillColor = UIColor.black.cgColor

        let pathToOverlay = UIBezierPath(rect: bounds)
        pathToOverlay.append(UIBezierPath(rect: rect))
        pathToOverlay.usesEvenOddFillRule = true
        maskLayer.path = pathToOverlay.cgPath

        layer.mask = maskLayer
    }
}

但是效果却出乎我的意料,为什么?

我需要周围的一切都像矩形当前那样模糊。而且里面的rect应该是透明的。

编辑::

我研究了下面的评论,并尝试了另一个答案,但结果还是一样。为什么?;)我不知道哪里出了问题。

private func makeClearHole(rect: CGRect) {
    let maskLayer = CAShapeLayer()
    maskLayer.fillColor = UIColor.black.cgColor

    let pathToOverlay = CGMutablePath()
    pathToOverlay.addRect(blurView.bounds)
    pathToOverlay.addRect(rect)
    maskLayer.path = pathToOverlay
    maskLayer.fillRule = .evenOdd
    blurView.layer.mask = maskLayer
}

好吧,我测试了您的代码,并且扩展中带有 makeClearHole 函数的原始代码工作正常!问题出在其他地方。

1- 改变 CoverView 如下*

class CoverView: UIView {
    private lazy var blurView: UIVisualEffectView = {
        let bv = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
        bv.frame = bounds
        return bv
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // MARK: - Internal

    func setup() {
        addSubview(blurView)
        blurView.snp.makeConstraints { maker in
            maker.edges.equalToSuperview()
        }
        blurView.makeClearHole(rect: CGRect(x: 100, y: 100, width: 100, height: 230))
    }
}

2- 在您的视图控制器中为 coverView 提供框架 您拥有的视图控制器不同。但是你应该给 CoverView 实例一个框架。这是这样的:(同样,这是我测试的方式,但你的视图控制器肯定不同)

class ViewController: UIViewController {

    var label: UILabel!
    var coverView: CoverView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        label = UILabel()
        label.text = "HELLO WORLD"
        label.font = UIFont.systemFont(ofSize: 40, weight: .black)
        
        
        coverView = CoverView(frame: CGRect(x: 20, y: 200, width: 300, height: 400))
        
        view.addSubview(label)
        view.addSubview(coverView)
        
        label.snp.makeConstraints { make in
            make.center.equalTo(view)
        }
        
        coverView.snp.makeConstraints { make in
            make.width.equalTo(coverView.bounds.width)
            make.height.equalTo(coverView.bounds.height)
            make.leading.equalTo(view).offset(coverView.frame.minX)
            make.top.equalTo(view).offset(coverView.frame.minY)
        }
    }


}

** 结果**