在UIBlurEffect上画一个洞

时间:2016-10-26 08:09:42

标签: ios objective-c swift overlay layer

Xcode 8.0 - Swift 2.3
我有一个内部扩展来创建效果很好的模糊层:

internal extension UIView {

    /**
     Add and display on current view a blur effect.
     */
    internal func addBlurEffect(style style: UIBlurEffectStyle = .ExtraLight, atPosition position: Int = -1) -> UIView {
        // Blur Effect
        let blurEffectView = self.createBlurEffect(style: style)
        if position >= 0 {
            self.insertSubview(blurEffectView, atIndex: position)
        } else {
            self.addSubview(blurEffectView)
        }
        return blurEffectView
    }

    internal func createBlurEffect(style style: UIBlurEffectStyle = .ExtraLight) -> UIView {
        let blurEffect = UIBlurEffect(style: style)
        let blurEffectView = UIVisualEffectView(effect: blurEffect)
        blurEffectView.frame = self.bounds
        blurEffectView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
        return blurEffectView
    }

}

问题是:如何在模糊叠加中添加形状的孔? 我做了很多尝试:

let p = UIBezierPath(roundedRect: CGRectMake(0.0, 0.0, self.viewBlur!.frame.width, self.viewBlur!.frame.height), cornerRadius: 0.0)
p.usesEvenOddFillRule = true
let f = CAShapeLayer()
f.fillColor = UIColor.redColor().CGColor
f.opacity = 0.5
f.fillRule = kCAFillRuleEvenOdd
p.appendPath(self.holePath)
f.path = p.CGPath
self.viewBlur!.layer.addSublayer(f)

但结果是:

enter image description here

我无法理解为什么UIVisualEffectView上的洞可以正常,但_UIVisualEffectBackdropView

中没有

更新

我试过@Arun解决方案(使用UIBlurEffectStyle.Dark),但结果不一样:

enter image description here

更新2

使用@ Dim_ov的解决方案,我有: enter image description here

为了完成这项工作,我需要以这种方式隐藏_UIVisualEffectBackdropView

    for v in effect.subviews {
        if let filterView = NSClassFromString("_UIVisualEffectBackdropView") {
            if v.isKindOfClass(filterView) {
                v.hidden = true
            }
        }
    }

3 个答案:

答案 0 :(得分:10)

在iOS 10中,您必须使用mask的{​​{1}}属性,而不是UIVisualEffectView的{​​{1}}。

我在iOS 10或Xcode 8的早期测试版的发行说明中看到了这一点,但我现在找不到这些注释:)。我会在找到后立即用适当的链接更新我的答案。

所以这是适用于iOS 10 / Xcode 8的代码:

CALayer

Swift 2.3版本:

mask

<强>更新

嗯,这是Apple Developer论坛的讨论,而不是iOS发行说明。但是Apple的代表也有答案,所以我认为,这些信息可能被视为“官方”。

讨论的链接:https://forums.developer.apple.com/thread/50854#157782

  

无法保证屏蔽视觉效果视图的图层   正确的结果 - 在iOS 9的某些情况下,它会产生一个   效果看起来不错,但可能来源错误。   视觉效果视图将不再提供不正确的内容,但是   屏蔽视图的唯一方法是使用cornerRadius   直接在视觉效果视图的层(应该产生的   你在这里尝试的结果相同)或使用视觉效果   view的maskView属性。

enter image description here

答案 1 :(得分:3)

请在此处查看我的代码

内部扩展UIView {

/**
 Add and display on current view a blur effect.
 */
internal func addBlurEffect(style style: UIBlurEffectStyle = .ExtraLight, atPosition position: Int = -1) -> UIView {
    // Blur Effect
    let blurEffectView = self.createBlurEffect(style: style)
    if position >= 0 {
        self.insertSubview(blurEffectView, atIndex: position)
    } else {
        self.addSubview(blurEffectView)
    }
    return blurEffectView
}

internal func createBlurEffect(style style: UIBlurEffectStyle = .ExtraLight) -> UIView {
    let blurEffect = UIBlurEffect(style: style)
    let blurEffectView = UIVisualEffectView(effect: blurEffect)
    blurEffectView.frame = self.bounds
    blurEffectView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
    return blurEffectView
}

}

类ViewController:UIViewController {

@IBOutlet weak var blurView: UIImageView!

var blurEffectView: UIView!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    blurEffectView = blurView.addBlurEffect(style: UIBlurEffectStyle.Light, atPosition: 0)


}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    let outerbezierPath = UIBezierPath.init(roundedRect: self.blurEffectView.frame, cornerRadius: 0)
    let rect = CGRectMake(150, 150, 100, 100)
    let innerCirclepath = UIBezierPath.init(roundedRect:rect, cornerRadius:rect.height * 0.5)
    outerbezierPath.appendPath(innerCirclepath)
    outerbezierPath.usesEvenOddFillRule = false
    let fillLayer = CAShapeLayer()
    fillLayer.fillRule = kCAFillRuleEvenOdd
    fillLayer.fillColor = UIColor.blackColor().CGColor
    fillLayer.path = outerbezierPath.CGPath
    self.blurEffectView.layer.mask = fillLayer
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

} 使用UIBlurEffectStyle.Light enter image description here

使用UIBlurEffectStyle.Dark enter image description here

使用UIBlurEffectStyle.ExtraLight enter image description here

答案 2 :(得分:0)

我的代码中遇到了同样的问题。我在包含UIView的{​​{1}}上应用了蒙版后,模糊消失了。但是,我可以通过覆盖父级的UIVisualEffectView方法将其转回:

draw

我不知道为什么它能正常工作,但希望它会帮助某人。我用来削减漏洞的代码:

override func draw(_ rect: CGRect) {
    super.draw(rect)
}