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

IosStoryboardUistoryboardIos13

Ios Problem Overview


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.

Ios Solutions


Solution 1 - Ios

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 - Ios

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 - Ios

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 - Ios

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 - Ios

Objective C Solutions and iOS 13

UINavigationBarAppearance* navBarAppearance = [self.navigationController.navigationBar standardAppearance];
        [navBarAppearance configureWithOpaqueBackground];
        navBarAppearance.titleTextAttributes = @{NSForegroundColorAttributeName:TitleColor};
        navBarAppearance.largeTitleTextAttributes = @{NSForegroundColorAttributeName: TitleColor};
        navBarAppearance.backgroundColor = TopColor;
        self.navigationController.navigationBar.standardAppearance = navBarAppearance;
        self.navigationController.navigationBar.scrollEdgeAppearance = navBarAppearance;

Solution 6 - Ios

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

Solution 7 - Ios

If you want to remove the underline below the nav bar

if #available(iOS 13.0, *) {
        let navBarAppearance = UINavigationBarAppearance()
        navBarAppearance.configureWithOpaqueBackground()
        navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
        navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
        navBarAppearance.backgroundColor = <yourColor>
        navBarAppearance.backgroundImage = UIImage()
        navBarAppearance.shadowImage = UIImage()
        navBarAppearance.shadowColor = .clear
        self.navigationController?.navigationBar.standardAppearance = navBarAppearance
        self.navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
   
    }

Solution 8 - Ios

For iOS 13 I was having a problem with the bar's shadow line showing up. Setting the Bars shadow image to nil solved that issue.

Before

func configureNavigation() {
        let navBarAppearance = UINavigationBarAppearance()
        navBarAppearance.configureWithOpaqueBackground()
        navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.myColor,
                                                     .font: UIFont(name: "MyFont", size: 42)!]
        navBarAppearance.backgroundColor = .white
        navigationController?.navigationBar.isTranslucent = false
        navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
    }

Image with shadow

After

func configureNavigation() {
        let navBarAppearance = UINavigationBarAppearance()
        navBarAppearance.configureWithOpaqueBackground()
        navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.myColor,
                                                     .font: UIFont(name: "MyFont", size: 42)!]
        navBarAppearance.backgroundColor = .white
        navBarAppearance.shadowColor = nil
        navigationController?.navigationBar.isTranslucent = false
        navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
    }

Image without shadow

Solution 9 - Ios

Fully workable code:

 let navigationBarAppearace = UINavigationBar.appearance()
    navigationBarAppearace.tintColor = .tintColor
    navigationBarAppearace.barTintColor = .barTintColor
    navigationBarAppearace.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.tintColor]

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

Good luck all, Peace!

Solution 10 - Ios

Thanks to Mike and Hans's answer. My case is half transparent status bar and nav bar with alpha 0.5. iOS13 seems complicated. Below is my test result, will work if you want transparent for both.

if #available(iOS 13.0, *) {
                let navBarAppearance = UINavigationBarAppearance()
                // This only set top status bar as transparent, not the nav bar.
                navBarAppearance .configureWithTransparentBackground()
                // This set the color for both status bar and nav bar(alpha 1).
                navBarAppearance.backgroundColor = UIColor.red.withAlphaComponent(0.5)
                navigationController?.navigationBar.standardAppearance = navBarAppearance
                navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
                // Nav bar need sets to translucent for both nav bar and status bar to be translucent.
                navigationController?.navigationBar.isTranslucent = true
                // // Need to reset nav bar's color to make it clear to display navBarAppearance's color
                navigationController?.navigationBar.backgroundColor = UIColor.clear
               } 

Solution 11 - Ios

I had a similar problem when updating one of my apps to be more iOS 13 compatible. As Hans mentioned above, the large titles are transparent by default. If you are a heavy Storyboard user as I am, there's another setting in the side bar that's easy to turn on.

If you click on your nav bar in the story board, it usually defaults to selecting the Navigation Item, and you won't get any customization options. Select the Navigation Bar option above it, and then you are able to choose a custom background color of whatever you want over in the Inspector on the right.

enter image description here

Solution 12 - Ios

I've discovered that with storyboards you have to fake the nav bar (only really works with opaque nav bars, assuming your green is opaque). The best way I found was to create a placeholder view (purple) that fits the safe area insets, and then add a fake view behind the nav bar (cyan/blue) that is the height remaining. Works for my project, but yeah it's a bit of a hack. Screenshot from Xcode 11 beta 4 displaying constraints required for status bar hack

Edit: This is mainly for LaunchScreen.storyboard where you can't use a custom view controller class.

Solution 13 - Ios

Swift 5 > override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { > super.traitCollectionDidChange(previousTraitCollection) >
> let userInterfaceStyle = traitCollection.userInterfaceStyle > modeDetect(userInterfaceStyle: userInterfaceStyle) >
> } >
> override func viewDidAppear(_ animated: Bool) { > navigationController?.navigationBar.barStyle = .black > navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.white] > } >
> func modeDetect(userInterfaceStyle: UIUserInterfaceStyle) { > switch userInterfaceStyle { > case .light: > navigationController?.navigationBar.barTintColor = .systemPink > case .dark: > navigationController?.navigationBar.barTintColor = .systemBackground > default: > break > } > }

Solution 14 - Ios

The following Objective-C code made iOS 13 navigation bar behave like the previous version for me:

	if (@available(iOS 13.0, *)) {
		// Setup iOS 13 navigation bar
		sharedSelector.navigationBar.scrollEdgeAppearance = sharedSelector.navigationBar.standardAppearance;
	} else {
		// Fallback on earlier versions
	}

Solution 15 - Ios

Call this function with a proper argument. This code is working properly.

open func showNavigationBar(large: Bool,
                            animated: Bool,
                            isTransparabar: Bool,
                            titleColor: UIColor,
                            barBackGroundColor: UIColor,
                            fontSize: CGFloat) {
        
        navigationController?.navigationBar.barTintColor = barBackGroundColor
        navigationController?.navigationBar.backgroundColor = barBackGroundColor
        navigationController?.navigationBar.isTranslucent = true
        self.navigationController?.setNavigationBarHidden(false, animated: animated)
        if large {
            self.navigationController?.navigationBar.prefersLargeTitles = true
            if #available(iOS 13.0, *) {
                let appearance = UINavigationBarAppearance()
                appearance.backgroundColor = barBackGroundColor
                appearance.titleTextAttributes = [.foregroundColor: titleColor]
                appearance.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: titleColor]
                
                navigationController?.navigationBar.standardAppearance = appearance
                navigationController?.navigationBar.compactAppearance = appearance
                navigationController?.navigationBar.scrollEdgeAppearance = appearance
            } else {
                self.navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: titleColor]
            }
        } else {
            self.navigationController?.navigationBar.prefersLargeTitles = false
            self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: titleColor!]
        }
    }

Solution 16 - Ios

I just turn on translucent in storyboard

like here

Solution 17 - Ios

Mike's solution is great.

I offer an alternative approach to change the UINavigationBar color which applies to any iOS version.

We are basically going to exploit the fact that we can set an Image as the UINavigationBar's background.

FIRST

Add an extension to generate a UIImage from any UColor. Note that you can also also write an extension later to generate UIColor from hexadecimals or other formats if you want.

extension UIColor {
    func image(_ size: CGSize = CGSize(width: 1, height: 1)) -> UIImage {
        return UIGraphicsImageRenderer(size: size).image { rendererContext in
            self.setFill()
            rendererContext.fill(CGRect(origin: .zero, size: size))
        }
    }
    
}

Thanks @neoneye for this great UIColor extension :)

SECOND

Now we get down to business:

private func setupNavigationBarAppearance(navBar: UINavigationBar) {
    navBar.isTranslucent = false
    let navBarColorImage = UIColor.blue.image()
    navBar.setBackgroundImage(navBarColorImage, for: .default)
    navBar.tintColor = UIColor.white
}

Because we've setup the opaque colored image as the background, we do not need to check for iOS 13.

I hope this help some folks to customize their NavBars.

Cheers!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionstevenView Question on Stackoverflow
Solution 1 - IosMikeView Answer on Stackoverflow
Solution 2 - IosmattView Answer on Stackoverflow
Solution 3 - IosHans KnöchelView Answer on Stackoverflow
Solution 4 - IoscvbView Answer on Stackoverflow
Solution 5 - Iosmohammad alabidView Answer on Stackoverflow
Solution 6 - IosFabioView Answer on Stackoverflow
Solution 7 - IosMirza Q AliView Answer on Stackoverflow
Solution 8 - IosAndrew EdwardsView Answer on Stackoverflow
Solution 9 - IosMihail SalariView Answer on Stackoverflow
Solution 10 - IosNingView Answer on Stackoverflow
Solution 11 - IosDrewView Answer on Stackoverflow
Solution 12 - IosSunburstEnzoView Answer on Stackoverflow
Solution 13 - IosDumexView Answer on Stackoverflow
Solution 14 - IosAndré PintoView Answer on Stackoverflow
Solution 15 - IosKiran SarvaiyaView Answer on Stackoverflow
Solution 16 - IosMedefView Answer on Stackoverflow
Solution 17 - IosBelfDevView Answer on Stackoverflow