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!

  • deleted

  • Hi, little bit late to the game, but i just got this in my app after compiling with xcode 13.

    I followed the advice from @Rincewind and got it working, with one exception: When you change the appearances, the navigation text, is then black, not white. The back arrow is still white though.

    I managed to sort this out by doing the "largeTextAttributes"-dance : coloredAppearance.titleTextAttributes = [.foregroundColor: UIColor.white] coloredAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]

    However, i am surprised that this is not mentioned by anyone in this thread. Howcome i am the only one having this color issue? Am i missing something?

    Pointers appreciated.

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

Accepted Reply

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).

  • Hi, Rincewind. Quick question. How do you change the Navigation Bar's tint color? The classes UINavigationBarAppearance, UIBarAppearance, and UIBarButtonItemAppearance do not include any tintColor property. The only way I found is with the tintColor property of the UINavigationBar, but this is a Legacy property and we are supposed to use appearances objects. For instance, how do you change the color of the image for the Back button? Thanks!

  • Have you tried applying it to UIImagePickerController? No luck when I tried it

  • Any solution on SwiftUI? Is this what is causing really ugly List animations inside NavigationView on 15 where the content goes 'behind' the navigation bar, i.e. FB9536532?

Replies

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]];
  }
  • This should be the accepted answer!

Add a Comment

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)

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.

  • It worked for me on Xcode 13.3.1. Thanks!

Add a Comment