Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fade a UIVisualEffectView and/or UIBlurEffect in and out?

I want to fade a UIVisualEffectsView with a UIBlurEffect in and out:

var blurEffectView = UIVisualEffectView()
blurEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))

I use a normal animation within a function called by a UIButton to fade it in, same for fading out but .alpha = 0 & hidden = true:

blurEffectView.hidden = false
UIView.animate(withDuration: 1, delay: 0, options: .curveEaseOut) {
    self.blurEffectView.alpha = 1
}

Now, fading in both directions does work but it gives me an error when fading out:

<UIVisualEffectView 0x7fdf5bcb6e80> is being asked to animate its opacity. This will cause the effect to appear broken until opacity returns to 1.

Question

How do I successfully fade the UIVisualEffectView in and out without breaking it and having a fading transition?

Note

  • I tried to put the UIVisualEffectView into a UIView and fade that one, no success
like image 846
LinusGeffarth Avatar asked Mar 27 '15 18:03

LinusGeffarth


3 Answers

I think this is new in iOS9, but you can now set the effect of a UIVisualEffectView inside an animation block:

let overlay = UIVisualEffectView()
// Put it somewhere, give it a frame...
UIView.animate(withDuration: 0.5) {
    overlay.effect = UIBlurEffect(style: .light)
}

Set it to nil to remove.

VERY IMPORTANT - When testing this on the simulator, make sure to set your simulator's Graphics Quality Override to High Quality in order for this to work.

like image 131
jrturton Avatar answered Nov 20 '22 13:11

jrturton


The Apple documentation (currently) states...

When using the UIVisualEffectView class, avoid alpha values that are less than 1.

and

Setting the alpha to less than 1 on the visual effect view or any of its superviews causes many effects to look incorrect or not show up at all.

I believe some important context is missing here...

I'd suggest that the intent is to avoid alpha values that are less than 1 for a persistent view. In my humble opinion this does not apply to the animation of a view.

My point - I'd suggest that alpha values less than 1 are acceptable for animations.

The terminal message states:

UIVisualEffectView is being asked to animate its opacity. This will cause the effect to appear broken until opacity returns to 1.

Reading this carefully, the effect will appear to be broken. My points on this being:

  • the apparent break only really matters for a view that is persistent - not changing;
  • a persistent / unchanging UIVisualEffect view with an alpha value less than 1 will not present as intended / designed by Apple; and
  • the message in the terminal is not an error, just a warning.

To extend @jrturton's answer above that helped me solve my problem, I'd add...

To fade out the UIVisualEffect use the following (Objective-C) code:

UIView.animateWithDuration(1.0, animations: {
//  EITHER...
    self.blurEffectView.effect = UIBlurEffect(nil)
//  OR...
    self.blurEffectView.alpha = 0
}, completion: { (finished: Bool) -> Void in
    self.blurEffectView.removeFromSuperview()
} )

I successfully use both methods: setting the effect property to nil and setting the alpha property to 0.

Note that setting the effect to nil creates a "nice flash" (for want of a better description) at the end of the animation, while setting the alpha to 0 creates a smooth transition.

(Let me know any syntax errors... I write in obj-c.)

like image 24
andrewbuilder Avatar answered Nov 20 '22 14:11

andrewbuilder


Here is the solution that I ended up which works on both iOS10 and earlier versions using Swift 3

extension UIVisualEffectView {

    func fadeInEffect(_ style:UIBlurEffectStyle = .light, withDuration duration: TimeInterval = 1.0) {
        if #available(iOS 10.0, *) {
            let animator = UIViewPropertyAnimator(duration: duration, curve: .easeIn) {
                self.effect = UIBlurEffect(style: style)
            }

            animator.startAnimation()
        }else {
            // Fallback on earlier versions
            UIView.animate(withDuration: duration) {
                self.effect = UIBlurEffect(style: style)
            }
        }
    }

    func fadeOutEffect(withDuration duration: TimeInterval = 1.0) {
        if #available(iOS 10.0, *) {
            let animator = UIViewPropertyAnimator(duration: duration, curve: .linear) {
                self.effect = nil
            }

            animator.startAnimation()
            animator.fractionComplete = 1
        }else {
            // Fallback on earlier versions
            UIView.animate(withDuration: duration) {
                self.effect = nil
            }
        }
    }

}

You can also check this gist to find an example usage.

like image 15
Gunhan Avatar answered Nov 20 '22 13:11

Gunhan