barTintColor not working in iOS 15

Hi,

When I run the following code in application(_ :didFinishLaunchingWithOptions) in iOS 15, the bar color turns transparent (thus, showing the black background underneath), while the same code works fine in iOS 14.5:

UINavigationBar.appearance().isTranslucent = false
UINavigationBar.appearance().barTintColor = .red

Here's the screenshots of Simulators running iOS 14.5 and iOS 15:

I'm using Xcode 13 on macOS Big Sur 11.4.

Thanks!

Answered by Frameworks Engineer in 678641022

In iOS 15, UIKit has extended the usage of the scrollEdgeAppearance, which by default produces a transparent background, to all navigation bars. The background is controlled by when your scroll view scrolls content behind the navigation bar. Your screenshots indicate that you are scrolled to the top, and so the navigation bar has selected its scrollEdgeAppearance over the standardAppearance that it would use when scrolled, and on previous versions of iOS.

To restore the old look, you must adopt the new UINavigationBar appearance APIs, UINavigationBarAppearance. Remove your existing customizations and do something like this:

let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = <your tint color>
navigationBar.standardAppearance = appearance;
navigationBar.scrollEdgeAppearance = navigationBar.standardAppearance

In the general case, it is the last line navigationBar.scrollEdgeAppearance = navigationBar.standardAppearance, which resolves the issue by having the UINavigationBar use the same appearance for both its standard and edge states. Also note that this will cause the scroll view to underlap the navigation bar – we recommend against setting UINavigationBar.isTranslucent = true.

You can also use the appearance proxy with the code above, but substituting navigationBar.appearance().scrollEdgeAppearance = appearance for the last line (as you are constructing your own appearance object – the idea is to just make sure both scrollEdge and standard appearances are the same).

In case it helps someone, placing @Rincewind's code snippet in applicationDidBecomeActive restored the pre-iOS15 look of the navigation bar and ensured the navigation controller background view color updated when the user changed between light and dark mode while the app was running.

      let appearance = UINavigationBarAppearance()
      appearance.configureWithOpaqueBackground()
      appearance.backgroundColor = color  // eg .black or .white
      nc.navigationBar.standardAppearance = appearance;
      nc.navigationBar.scrollEdgeAppearance = nc.navigationBar.standardAppearance

In case someone is having issues with navigation title font and color, add the following code to your extension


     if let attributes = self.navigationController?.navigationBar.largeTitleTextAttributes {
        barAppearance.largeTitleTextAttributes = attributes
      }
       
      if let attributes = self.navigationController?.navigationBar.titleTextAttributes {
        barAppearance.titleTextAttributes = attributes
      }

hope it helps

Mathias_, you are not alone, I have the same issue, navigation text is black not white.

I'm having that problem too, but even largeTitleTextAttributes doesn't do it for me. Does anyone got a solution?

found this, that did it for me: https://sarunw.com/posts/uinavigationbar-changes-in-ios13/

basically, set everything in the specific appearance instead in the navigationbar / navigationcontroller

In order to change it everywhere put this code into didFinishLaunchingWithOptions:

if (@available(iOS 15.0, *)) {
    UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];
    [appearance setBackgroundColor:[UIColor grayColor]];
    [[UINavigationBar appearance] setScrollEdgeAppearance:appearance];
    [[UINavigationBar appearance] setStandardAppearance:appearance];
    [[UINavigationBar appearance] setTintColor:[UIColor grayColor]];
  }

For SwiftUI I found the best thing to do is use the UINavigationBarAppearance() method, then add the .id() to the NavigationView. This will automatically redraw the component when the color changes. Now you can have reactive color changes based on a state engine.

let custom = UINavigationBarAppearance()
custom.configureWithOpaqueBackground()
custom.backgroundColor = color
UINavigationBar.appearance().standardAppearance = custom
UINavigationBar.appearance().scrollEdgeAppearance = custom
UINavigationBar.appearance().compactAppearance = custom
UINavigationBar.appearance().compactScrollEdgeAppearance = custom

Then in the SwiftUI

NavigationView {
  content
}
  .id(color.description)

On iOS 15.2 experiencing issues with both nav bar and tab bar colors messed up. But only when build with Xcode 13. App in prod build with Xcode 12 is looking fine on iOS 15.2

Anyhow, checked out the suggestion from the link T_T_T posted and added a snippet to AppDelegate and it resolved it at least for the nav bar. Thanks for sharing T_T_T!

I was able to solve this using the attributes inspector as follows:

Select the navigation bar. At the top of the attributes inspector, check the box next to Scroll Edge. Under 'Scroll Edge Bar Button Appearances', find the bar tint menu and select the desired color.

barTintColor not working in iOS 15
 
 
Q