Blur/Unblur 作为协议扩展的功能

Blur/Unblur function as a protocol extension

我创建了 Blurable 协议,其扩展名具有 blur 功能。

protocol Blurable {}

extension Blurable where Self: UIView {

    func blur(with effect:  UIBlurEffectStyle) {
        let blurEffect = UIBlurEffect(style: effect)
        let blurEffectView = UIVisualEffectView(effect: blurEffect)

        blurEffectView.frame = bounds
        addSubview(blurEffectView)
    }
}

现在我想添加 unblur 功能。 如果它是 class,我会将 blurEffectView 作为 class 属性 并创建 unblur 函数像这样:

func unblur() {
    blurEffectView.removeFromSuperview
}

由于协议扩展不允许存储属性,这个问题的正确解决方案是什么?

您可以在协议声明中保留变量。

protocol Blurable: class {
    var blurEffectView: UIVisualEffectView? { set get }

    func applyBlur(with effect: UIBlurEffectStyle)
    func removeBlur() 
}

private var xoAssociationKey: UInt8 = 0

extension Blurable where Self: UIView {

    // If you want to avoid adding "blurEffectView" to each UIView class, 
    // you can do it this way
    var blurEffectView: UIVisualEffectView? {
        get {
            return objc_getAssociatedObject(self, &xoAssociationKey) as? UIVisualEffectView
        }

        set(newBlurEffectView) {
            objc_setAssociatedObject(self, &xoAssociationKey, newBlurEffectView, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
        }
    }

    func applyBlur(with effect: UIBlurEffectStyle) {
        let blurEffect = UIBlurEffect(style: effect)
        blurEffectView = UIVisualEffectView(effect: blurEffect)

        blurEffectView?.frame = bounds

        if let blurEffectView = blurEffectView { addSubview(blurEffectView) }
    }

    func removeBlur() {
        if let blurEffectView = blurEffectView {
            blurEffectView.removeFromSuperview()
        }

        blurEffectView = nil
    }
}

这应该有效。您可以将 blurEffectView 保留为非可选变量,但此解决方案在未来的更改中更加安全和有效,因为您可以通过编程方式检查是否应用了模糊。

var someView = SomeView()

if let _ = someView.blurEffectView {
    print("YEAP")
} else {
    print("NOPE")
}

我用过这个-

extension UIView {
    func blur() {
        let blurEffect = UIBlurEffect(style: .light)
        let blurEffectView = UIVisualEffectView(effect: blurEffect)
        blurEffectView.frame = self.bounds
        blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        self.addSubview(blurEffectView)
    }

    func unBlur() {
        for subview in self.subviews {
            if subview is UIVisualEffectView {
                subview.removeFromSuperview()
            }
        }
    }
}

您还可以添加标签并通过检查其标签来删除视图,但我觉得这是更好的选择。扩展也可用 here.