How do you programmatically change the alpha of a UIVisualEffectView in a NavigationBar?

假如想象 提交于 2021-02-07 08:25:08

问题


I have a scroll view that I'm using to control the alpha of other elements depending on how far down the view the user scrolls.

First, I set up the blur view. Alpha here doesn't seem to take, firstly

var effect: UIBlurEffectStyle = .light
if #available(iOS 10.0, *) {
    effect = .prominent
}
let blurView = UIVisualEffectView(effect: UIBlurEffect(style: effect))
blurView.alpha = 0
if let navigationBar = navigationController?.navigationBar {
    blurView.frame = navigationBar.bounds
}
self.blurView = blurView

Then in my UIScrollViewDelegate:

func scrollViewDidScroll(_ scrollView: UIScrollView) {
        var alpha = (scrollView.contentOffset.y / 200)
        alpha = alpha > 1.0 ? 1.0 : alpha

        blurView?.alpha = alpha
}

This doesn't seem to be working either.

Any advice on how to achieve this effect? Thanks!


回答1:


When you read the Apple documentation you can find:

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

In fact you should obtain also a warning:

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

P.S.: Pay attention, what I mean is that you can change the alpha of the visual effects but the view could appear as simply partially transparent rather than blurred.

If you don't believe in this documentation, you can test my little example below to a blank project and you can see that, if you change alpha value, your effect stop to work correctly:

(You can find all the project below to my GitHUB repository here)

Prepare in a blank project a navigationController connected to a viewController like this:

Put a generic image with an UIImageView to the view of your viewController, like this image:

class ViewController: UIViewController {
    var blurView: UIVisualEffectView!
    var effect: UIBlurEffectStyle = .light
    var blurEffect : UIBlurEffect!
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        // This code make more transparent our navigation
        if let navigationBar = navigationController?.navigationBar {
            navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
            navigationBar.tintColor = .white
            let textAttributes = [NSForegroundColorAttributeName:UIColor.white]
            navigationBar.titleTextAttributes = textAttributes
            navigationBar.shadowImage = UIImage()
            navigationBar.backgroundColor = UIColor(red: 0.0, green: 0.3, blue: 0.5, alpha: 0.3)
            navigationBar.isTranslucent = true
        }
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        if #available(iOS 10.0, *) {
            effect = .prominent
        } else {
            // Fallback on earlier versions
        }
        if let navigationBar = navigationController?.navigationBar {
            let noEffectView = UIVisualEffectView.init(frame: navigationBar.bounds)
            self.blurEffect = UIBlurEffect(style: effect)
            self.blurView = noEffectView
            navigationBar.addSubview(self.blurView)
            // This line below to don't blur buttons and title
            navigationBar.sendSubview(toBack: self.blurView)
            // Apply the effect:
            Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.applyBlur), userInfo: nil, repeats: false)
        }
    }
    func applyBlur() {
        print("Apply the blur effect..")
        UIView.animate(withDuration: 10.2, animations: {
            self.blurView.effect = self.blurEffect
        }, completion:{ (finished: Bool) in
            // Make test with a simple timer:
            Timer.scheduledTimer(timeInterval: 0.3, target: self, selector: #selector(self.changeAlpha), userInfo: nil, repeats: true)
        })
    }
    func changeAlpha() {
        let startNum:CGFloat = 0.0; let stopNum:CGFloat = 200.0
        let randomNum = CGFloat(arc4random()) / CGFloat(UINT32_MAX) * abs(startNum - stopNum) + min(startNum, stopNum)
        var alpha = (randomNum / 200)
        alpha = alpha > 1.0 ? 1.0 : alpha
        print("we change alpha to : \(alpha)")
        self.blurView.alpha = alpha
    }
}

Output with the blur effect:

Output during alpha changes:

A solution:

Probably you don't want to change the alpha value but the amount of blur effect during the scrolling so the solution could be to use the new fractionComplete of UIViewPropertyAnimator property available only from iOS 10.0 (as suggested in this other SO answer)

import UIKit
@available(iOS 10.0, *)
class ViewController: UIViewController {
    var blurView: UIVisualEffectView!
    var effect: UIBlurEffectStyle = .light
    var blurEffect : UIBlurEffect!
    var animator: UIViewPropertyAnimator!
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        // This code make more transparent our navigation
        if let navigationBar = navigationController?.navigationBar {
            navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
            navigationBar.tintColor = .white
            let textAttributes = [NSForegroundColorAttributeName:UIColor.white]
            navigationBar.titleTextAttributes = textAttributes
            navigationBar.shadowImage = UIImage()
            navigationBar.backgroundColor = UIColor(red: 0.0, green: 0.3, blue: 0.5, alpha: 0.3)
            navigationBar.isTranslucent = true
        }
    }
    override func viewDidLoad() {
        super.viewDidLoad()
            effect = .prominent
            if let navigationBar = navigationController?.navigationBar {
                let noEffectView = UIVisualEffectView.init(frame: navigationBar.bounds)
                self.blurEffect = UIBlurEffect(style: effect)
                self.blurView = noEffectView
                navigationBar.addSubview(self.blurView)
                // This line below to don't blur buttons and title
                navigationBar.sendSubview(toBack: self.blurView)
                // Apply the effect:
                Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.applyBlur), userInfo: nil, repeats: false)
            }
    }
    func applyBlur() {
        print("Apply the blur effect..")
        animator = UIViewPropertyAnimator(duration: 0.5, curve: .linear)
        self.blurView.effect = self.blurEffect
        animator.addAnimations {
            self.blurView.effect = nil
        }
        Timer.scheduledTimer(timeInterval: 0.3, target: self, selector: #selector(self.changeBlurFraction), userInfo: nil, repeats: true)

    }
    func changeBlurFraction() {
        let startNum:CGFloat = 0.0; let stopNum:CGFloat = 200.0
        let randomNum = CGFloat(arc4random()) / CGFloat(UINT32_MAX) * abs(startNum - stopNum) + min(startNum, stopNum)
        var blurFraction = (randomNum / 200)
        blurFraction = blurFraction > 1.0 ? 1.0 : blurFraction
        print("we change the blur fraction to : \(blurFraction)")
        animator.fractionComplete = blurFraction
    }
}

As you can see this change the blur effect not the alpha and every time the timer is fired you can see a different value of blur to your navigationBar.

The trick is to apply the blur effect and add a new animation to report the effect to nil but everytime with a new "fraction" to change the animation to that exact value of blur.

Output:




回答2:


Swift 5.0. Just use code below:

navigationController?.navigationBar.isTranslucent = false

It changes '0.85 alpha effect' with solid color with alpha = 1.




回答3:


Alpha blending of a UIVisualEffectView is broken as of iOS 10, along with layer masking, due to internal change to the implementation by Apple.

I'd suggest using a UIView​Property​Animator object to transition from the actual effect (.prominent, in your case) to nil, and then manually set the fractionComplete to be the alpha value. It will give you a much better effect and allow you to interactively change the effect.



来源:https://stackoverflow.com/questions/43099786/how-do-you-programmatically-change-the-alpha-of-a-uivisualeffectview-in-a-naviga

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!