In iOS13 the status bar background colour is different from the navigation bar in large text mode

71,865

Solution 1

No hacks or funkiness required here. The key is defining the desired appearance and setting this value on BOTH the nav bar's standardAppearance AND its scrollEdgeAppearance. I have the following in the init for my base navigation controller subclass for my entire app:

if #available(iOS 13.0, *) {
    let navBarAppearance = UINavigationBarAppearance()
    navBarAppearance.configureWithOpaqueBackground()
    navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
    navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
    navBarAppearance.backgroundColor = <insert your color here>
    navigationBar.standardAppearance = navBarAppearance
    navigationBar.scrollEdgeAppearance = navBarAppearance
}

enter image description here

Solution 2

If the problem is that you'd like to give the navigation bar a color when the large title is showing, use the new UINavigationBarAppearance class.

let app = UINavigationBarAppearance()
app.backgroundColor = .blue
self.navigationController?.navigationBar.scrollEdgeAppearance = app

Solution 3

On iOS 13, navigation bars using large title have a transparent color per Apple human interface guidelines. See more infos here:

In iOS 13 and later, a large title navigation bar doesn’t include a background material or shadow by default. Also, a large title transitions to a standard title as people begin scrolling the content

Solution 4

Universal code

let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.backgroundColor = // your color
navBarAppearance.shadowImage = nil // line
navBarAppearance.shadowColor = nil // line
UINavigationBar.appearance(whenContainedInInstancesOf: [UINavigationController.self]).standardAppearance = navBarAppearance
UINavigationBar.appearance(whenContainedInInstancesOf: [UINavigationController.self]).scrollEdgeAppearance = navBarAppearance

Solution 5

my navigationBar extension, iOS 13 Swift 5

extension UIViewController {
func configureNavigationBar(largeTitleColor: UIColor, backgoundColor: UIColor, tintColor: UIColor, title: String, preferredLargeTitle: Bool) {
    if #available(iOS 13.0, *) {
        let navBarAppearance = UINavigationBarAppearance()
        navBarAppearance.configureWithOpaqueBackground()
        navBarAppearance.largeTitleTextAttributes = [.foregroundColor: largeTitleColor]
        navBarAppearance.titleTextAttributes = [.foregroundColor: largeTitleColor]
        navBarAppearance.backgroundColor = backgoundColor

        navigationController?.navigationBar.standardAppearance = navBarAppearance
        navigationController?.navigationBar.compactAppearance = navBarAppearance
        navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance

        navigationController?.navigationBar.prefersLargeTitles = preferredLargeTitle
        navigationController?.navigationBar.isTranslucent = false
        navigationController?.navigationBar.tintColor = tintColor
        navigationItem.title = title

    } else {
        // Fallback on earlier versions
        navigationController?.navigationBar.barTintColor = backgoundColor
        navigationController?.navigationBar.tintColor = tintColor
        navigationController?.navigationBar.isTranslucent = false
        navigationItem.title = title
    }
}}

How to use:

configureNavigationBar(largeTitleColor: .yourColor, backgoundColor: .yourColor, tintColor: .yourColor, title: "YourTitle", preferredLargeTitle: true)

Set ViewController-based status bar...... to NO in info.plist if you want light Content

If you don't want largeTitles set it to false

Tested on iOS 13, hope this help :)

Share:
71,865

Related videos on Youtube

steven
Author by

steven

Updated on December 22, 2021

Comments

  • steven
    steven over 2 years

    Problems demo

    Pre-conditions to reproduce the problem:

    1. Xcode 11 beta + iOS 13 (latest version until Jun. 12 2019)
    2. The navigation bar is in Large text mode
    3. Specify the colour of navigation bar.

    The status bar will remain in white in a real device, above the green navigation bar.

    Solutions I tried:

    1. Revert it back to iOS12 will solve it, but we will encounter iOS13 eventually...
    2. disabling the large text mode will solve it...
    3. hide the status bar will fix it, but it will cause status text overlapping with navigation bar item.

    Any ideas? appreciate any help.

  • Reshad
    Reshad almost 5 years
    so what is the solution for having a large title and wanting a custom bartint color?
  • matt
    matt almost 5 years
    @Reshad Use the UINavigationBarAppearance class.
  • McDonal_11
    McDonal_11 almost 5 years
    Can u help me on this? Value of type 'UINavigationBar' has no member 'scrollEdgeAppearance'
  • matt
    matt almost 5 years
    Yes it does. developer.apple.com/documentation/uikit/uinavigationbar/… Remember this is iOS 13 we're talking about.
  • Mike
    Mike almost 5 years
    @Reshad see my answer below
  • matt
    matt almost 5 years
    Makes no sense to set the appearance background color to red and then make the background color clear.
  • Ely
    Ely almost 5 years
    Your example code uses a custom Theme extension on UIColor, which makes it a bit hard to understand
  • CenoX
    CenoX almost 5 years
    This method has one issue about when user changing their theme (eg. light -> dark ) when app running in background. Other stuff changes its color but only navigation bar tint color remains. You can easily see that. Just run app in simulator and change appearence from Developer setting in Settings app. tried overriding traitCollectionDidChange and still got error. any ideas on that?
  • Sebastian
    Sebastian almost 5 years
    Don't forget about compactAppearance!
  • ShadeToD
    ShadeToD almost 5 years
    @CenoX , I found quick and easy solution for your problem. First , create new color set in assets catalog. Change appearances from "None" to "Any, Light, Dark". Choose whatever colors u want. Second step is to load your custom UIColor in code. Use "let customColor = UIColor(named "CustomColor") , change name"CustomColor" to your asset name. Last step is to assign the color to our bar background.
  • CenoX
    CenoX almost 5 years
    I think that is very good solution @ShadeToD. I'm gonna try to my application, Thanks.
  • Jim B
    Jim B almost 5 years
    Better use these three UINavigationBar.appearance() statements for universal usage: UINavigationBar.appearance().standardAppearance = navBarAppearance UINavigationBar.appearance().compactAppearance = navBarAppearance UINavigationBar.appearance().scrollEdgeAppearance = navBarAppearance
  • stepheaw
    stepheaw over 4 years
    I'm having a hard time seeing the difference between the before and after
  • Andrew Edwards
    Andrew Edwards over 4 years
    If SO isn't showing them in the browser then I'd try either another screen or Download the images and look at them in review for example.
  • benc
    benc over 4 years
    @stepheaw: there's a thin, very-dark line right on the grey<->white boundary...
  • bgolson
    bgolson over 4 years
    Add in a call to self.navigationController?.navigationBar.setNeedsLayout() if you're doing this after viewDidLoad()
  • Emon
    Emon over 4 years
    Thank you very much man.I wish i could give you more like for this.
  • Fabio
    Fabio over 4 years
    @Emon Thx! I'm happy to have helped you :)
  • André Pinto
    André Pinto over 4 years
    @deepak-verma I should have mentioned that I'm using Objective-C and not Swift, so the syntax was correct for me.
  • Pavel Lahoda
    Pavel Lahoda over 4 years
    While this approach works, it is not the best idea to set NavigationBar properties using the UINavigationBarAppearance for each UIViewController instance, as the UINavigationBarAppearance is shared (there is just one appearance at time) - this can lead to rather ugly effects in cases where both Controllers are visible, such as when you perform (slow) swipe-left-edge-to-go-back navigation gesture.
  • Fabio
    Fabio over 4 years
    @PavelLahoda Your answer is correct, but the new OS creates some problems to show large titles ... The correct approach sometimes does not work and above all very rarely you use the swipe to go back when using the navigation controller but the button created automatically in the child controller ... However to be more secure just disable the swipe to go back (which in iOS is useless and not very functional). In all cases, thanks for your comment, it will certainly be useful for those who will read us later :)
  • Ric Santos
    Ric Santos over 4 years
    No need to set compactAppearance as "If not set, the standardAppearance will be used instead."
  • benc
    benc about 4 years
    I just implemented the conventional approach via Xcode 11, but I like your thinking. :)
  • user
    user over 3 years
    Obligatory "This is stupid, Apple" comment
  • Starsky
    Starsky over 3 years
    If you're changing these values dynamically in the app, like letting the user select his own app theme, then you will need to call navigationController?.navigationBar.layoutSubviews() in order to apply the changes instantly.
  • jxd
    jxd over 3 years
    When doing this, it doesn't match the Statusbar color.
  • Konstantin Nikolsky
    Konstantin Nikolsky over 2 years
    Dude, you've made my day, thanks.