How to disable automatic transparent navbar in iOS 15

Xcode 13 along with iOS 15 SDK brings substantial changes to UINavigationBar.

Published: Oct. 6, 2021
App Store

Apple updated how navigation bars look in iOS 15 (once your app is build with Xcode 13) and now they are by default transparent if there isn't any content behind them.

So in practice this means that the old "bar" with different background is now gone and comes back only after you scrolled the content.

Because this is enabled by default, it might cause visual issues for your app. I had to fix this in couple apps and here is how do to it.

You need to use the UINavigationBarAppearance which is available since iOS 13.

Restoring pre-iOS15 look

Apologies for the syntax coloring.. looks like the #available is causing issues

The basic fix looks like this:

if #available(iOS 15.0, *) { 
    let navigationBarAppearance = UINavigationBarAppearance() 
    navigationBarAppearance.configureWithDefaultBackground() 
    UINavigationBar.appearance().standardAppearance = navigationBarAppearance 
    UINavigationBar.appearance().compactAppearance = navigationBarAppearance 
    UINavigationBar.appearance().scrollEdgeAppearance = navigationBarAppearance 
} 

The configureWithDefaultBackground makes the navigation bar appear as translucent.

The main key here is that we are setting the new scrollEdgeAppearance to be the same as standard one. This turns off the automatic transparency for all navigation bars in your app, since with the UINavigationBar.appearance() we are using the appearance proxy. The code above should ideally go to AppDelegate when the app starts.

Toggling transparency with this API

Another issue I had to solve was that the app I needed to fix toggled navigation bar to be transparent on some screens and the old way of doing this no longer worked with Xcode 13.

The switching now looks like this:

if #available(iOS 15.0, *) {
    if isTransparent {
        let navigationBarAppearance = UINavigationBarAppearance()
        navigationBarAppearance.configureWithTransparentBackground()

        navigationController.navigationBar.tintColor = .white

        navigationItem.scrollEdgeAppearance = navigationBarAppearance
        navigationItem.standardAppearance = navigationBarAppearance
        navigationItem.compactAppearance = navigationBarAppearance

    } else {
        let navigationBarAppearance = UINavigationBarAppearance()
        navigationBarAppearance.configureWithDefaultBackground()

        navigationController.navigationBar.tintColor = .label

        navigationItem.scrollEdgeAppearance = navigationBarAppearance
        navigationItem.standardAppearance = navigationBarAppearance
        navigationItem.compactAppearance = navigationBarAppearance
    }

    navigationController.setNeedsStatusBarAppearanceUpdate()
}

Of course the colors used here are for illustration. Feel free to use any other. Don't forget you can use the preferredStatusBarStyle property to control which style should the system status bar use.

Filip Němeček profile photo

WRITTEN BY

Filip Němeček @nemecek_f@iosdev.space

iOS blogger and developer with interest in Python/Django. Want to see most recent projects? 👀

iOS blogger and developer with interest in Python/Django. Want to see most recent projects? 👀