Search code examples
iosswiftuinavigationcontrolleruinavigationbarswift3

Navigation bar color is not under status bar


I am trying to make a transparent navigation bar, but when I set it to transparent It looks like this... : transparent

I want it to look like this non-transparent

but transparent and blurred like in the App Store but with background color. The problem is that the background color of the navigation controller is not under status bar like normal.

My code:

 self.navigationItem.title = "label"
 self.navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
 self.navigationBar.shadowImage = UIImage()
 self.navigationBar.isTranslucent = true
 self.navigationBar.backgroundColor = UIColor.init(red: 255/255, green: 0, blue: 0, alpha: 0.7)

EDIT: I have a custom class for UINavigationController and the view controller is embedded in a UINavigationController

Swift 3, Xcode 8.0 beta 5.


Solution

  • Let's break this problem into parts. First, you will need to use a UIVisualEffectView created with a UIBlurEffect to get the blurred/transparent effect that you want. Then you will need to figure out how to display that in the navigation bar so that it fills the whole nav bar and that status bar.

    Part 1

    I created a subclass of UIVisualEffectView in order to add a gradient. We can use this view to create the desired blurred/transparent effect.

    class GradientVisualEffectView: UIVisualEffectView {
    
        private let gradient: CAGradientLayer = {
            // You can tweak these colors and their alpha to get the desired gradient.
            // You can also mess with the gradient's locations.
            $0.colors = [
                UIColor.white.withAlphaComponent(0.3).cgColor, 
                UIColor(red: 1, green: 0, blue: 0, alpha: 0.7).cgColor
            ]
            return $0
        } (CAGradientLayer())
    
    
        override init(effect: UIVisualEffect?) {
            super.init(effect: effect)
            layer.addSublayer(gradient)
        }
    
        override func layoutSubviews() {
            super.layoutSubviews()
    
            // Make sure the gradient's frame always matches the blur effect.
            gradient.frame = bounds
        }
    
    }
    

    Part 2

    Now we need to use this view in the nav bar. I did this in a UIViewController that is embedded in a UINavigationController.

    override func viewDidLoad() {
        super.viewDidLoad()
    
        // Remove the nav bar's background
        let navBar = navigationController!.navigationBar
        navBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
        navBar.backgroundColor = .clear
    
        // Create the blur/transparent view. You can mess with styles here to get
        // different effects.
        let gradientBlur = GradientVisualEffectView(effect: UIBlurEffect(style: .light))
        gradientBlur.translatesAutoresizingMaskIntoConstraints = false
        navBar.addSubview(gradientBlur)
    
        // Constrain the view so that it always matches the nav bar.
        // The top constraint has a -20 constant so that it will extend above
        // the nav bar to the status bar.
        gradientBlur.leftAnchor.constraint(equalTo: navBar.leftAnchor).isActive = true
        gradientBlur.topAnchor.constraint(equalTo: navBar.topAnchor, constant: -20).isActive = true
        gradientBlur.rightAnchor.constraint(equalTo: navBar.rightAnchor).isActive = true
        gradientBlur.bottomAnchor.constraint(equalTo: navBar.bottomAnchor).isActive = true
    }
    

    Below is a picture of the result from my simulator. You can see some blurred text at the top left of the picture, where the white part of the status bar looks darker.

    blurred/transparent nav bar