Xcode 11.4. Navigation's Title Color gone BLACK from storyboard
Asked Answered
A

8

58

I recently updated my Xcode to 11.4. When I run the app on the device, i've noticed that all my navigations item's titles gone fully black when being set from storyboard. enter image description here

You can't change neither from code, the following line of code doesn't work anymore

self.navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.white]

I only make it work using some iOS 13 stuffs UINavigationBarAppearance

@available(iOS 13.0, *)
    private func setupNavigationBar() {
        let app = UINavigationBarAppearance()
        app.titleTextAttributes = [.foregroundColor: UIColor.white]
        app.backgroundColor = Constants.Color.barColor
        self.navigationController?.navigationBar.compactAppearance = app
        self.navigationController?.navigationBar.standardAppearance = app
        self.navigationController?.navigationBar.scrollEdgeAppearance = app

        self.navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.white]
    }

Can somebody explain me why??? This is a crucial bug, or some new hidden feature?

Abdominal answered 25/3, 2020 at 12:23 Comment(4)
Same problem here and i find nothing to do for correct this. I think it's a bug :/Osyth
Apple. Uggh. Really?Evulsion
try this one https://mcmap.net/q/917677/-why-doesn-39-t-my-ios-app-disable-dark-modeSnob
it is Xcode Interface builder Bug Update XCode to 11.4.1Subclinical
S
10

Apple finally fixed it in version 11.4.1

https://developer.apple.com/documentation/xcode_release_notes/xcode_11_4_1_release_notes

Sewerage answered 15/4, 2020 at 21:28 Comment(0)
D
39

This fixed it for me, using UINavigationBarAppearance instead, from: Customizing Your App’s Navigation Bar

if #available(iOS 13.0, *) {
    let appearance = UINavigationBarAppearance()
    appearance.configureWithOpaqueBackground()
    appearance.backgroundColor = UIColor.black
    appearance.titleTextAttributes = [.foregroundColor: UIColor.white] // With a red background, make the title more readable.
    self.navigationBar.standardAppearance = appearance
    self.navigationBar.scrollEdgeAppearance = appearance
    self.navigationBar.compactAppearance = appearance // For iPhone small navigation bar in landscape.
} else {
    self.navigationBar.barTintColor = UIColor.black
    self.navigationBar.tintColor = UIColor.white
    self.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.white]
}

Note: I subclassed UINavigationController, and this was called from the override of viewWillAppear.

...or for AppDelegate, app-wide:

if #available(iOS 13.0, *) {
    let appearance = UINavigationBarAppearance()
    appearance.configureWithOpaqueBackground()
    appearance.backgroundColor = UIColor.black
    appearance.titleTextAttributes = [
        NSAttributedStringKey.foregroundColor: UIColor.white
    ]

    let buttonAppearance = UIBarButtonItemAppearance()
    buttonAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.white]
    appearance.buttonAppearance = buttonAppearance

    UINavigationBar.appearance().standardAppearance = appearance
    UINavigationBar.appearance().scrollEdgeAppearance = appearance
    UINavigationBar.appearance().compactAppearance = appearance

    UIBarButtonItem.appearance().tintColor = UIColor.white
} else {
    UINavigationBar.appearance().barTintColor = UIColor.black
    UINavigationBar.appearance().titleTextAttributes = [
        NSAttributedStringKey.foregroundColor: UIColor.white
    ]
    UINavigationBar.appearance().tintColor = UIColor.white

    UIBarButtonItem.appearance().tintColor = UIColor.white
}

...for AppDelegate, app-wide, in Objective-C:

if (@available(iOS 13, *)) {
    UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];
    [appearance configureWithOpaqueBackground];
    appearance.backgroundColor = UIColor.whiteColor;
    appearance.titleTextAttributes = titleAttributes;

    UIBarButtonItemAppearance *buttonAppearance = [[UIBarButtonItemAppearance alloc] init];
    buttonAppearance.normal.titleTextAttributes = barButtonItemAttributes;
    appearance.buttonAppearance = buttonAppearance;

    UINavigationBar.appearance.standardAppearance = appearance;
    UINavigationBar.appearance.scrollEdgeAppearance = appearance;
    UINavigationBar.appearance.compactAppearance = appearance;

    [[UINavigationBar appearance] setTintColor:UIColor.blackColor];
} else {
    [[UINavigationBar appearance] setBarTintColor:UIColor.whiteColor];
    [[UINavigationBar appearance] setTintColor:UIColor.blackColor];
    [[UINavigationBar appearance] setTranslucent:false];
    [[UINavigationBar appearance] setTitleTextAttributes: titleAttributes];
    [[UIBarButtonItem appearance] setTitleTextAttributes:barButtonItemAttributes forState:UIControlStateNormal];
}
Delivery answered 25/3, 2020 at 23:50 Comment(10)
Thank you , this is a correct answer ! , on iOS 13 Apple added UINavigationBarAppearance() and for no reason on old Xcode we didn't nead to depend on it , but since Xcode 11.4 it must use UINavigationBarAppearance() or Title color will be always Black color.Mews
appearance.largeTitleTextAttributes for large titles.Chromic
This works great and thank you!, Is there anyway to do this universally from the AppDelegate?Calcariferous
@Calcariferous - Yep! See my updated answer, for an example. Cheers.Delivery
This changes the tint to white, though. I want my navigation bar to remain the color it is. If I comment out the lines in this code relating to tint, it still gives me a white colored nav bar.Screenplay
Thank you! you helped me a lot!Silvestro
In addition if you want to reduce code a bit -> If you just set the appearance().standard, scrollEdgeAppearance & compactAppearance will default to this also.Cathycathyleen
@Richard - I just added the answer for Objective-C. Sorry, I didn't see your comment until today.Delivery
Thank you, this works for me. Although on my first viewcontroller the title is still black. But when getting to the next one it is white, and when getting back to the first one then it is also white. Any suggestions?Planarian
Nope this answer is now out of date, it was an Xcode 11.4 bug and no fixed in 11.4.1 as mentioned by other posters.Arminius
W
14

On the storyboard, for your Navigation Controller change the "Bar Tint" to its "Default" value, then on your code you can change it as you normally would.

Wraf answered 28/3, 2020 at 6:32 Comment(7)
Best answer. Really.Bridgettbridgette
This is the proper wayBensky
Best anwer❗️ period.Simitar
I don't agree this is the best answer at all. There are legitimate reasons for wanting to change the Tint from the default color.Screenplay
@Screenplay yup, that's right. But with Xcode 11.4 if you don't set the default color in the storyboard, changing it programmatically it doesn't work. I don't know if this is an issue or not.Simitar
This is a Magic!Androus
This could be best answer.Larsen
S
10

Apple finally fixed it in version 11.4.1

https://developer.apple.com/documentation/xcode_release_notes/xcode_11_4_1_release_notes

Sewerage answered 15/4, 2020 at 21:28 Comment(0)
O
7

Not sure if it's a bug or not.

The way we fixed it is by setting the "Status Bar Style" to either dark or light content in project setting. This will force the Status Bar text color a certain way rather than being determined based on the devices being in Light or Dark mode.

In addition, you need to set the value "View controller-based status bar appearance" to "NO" in your Info.plist. without that value the "Status Bar style" will be overridden.

Next create a custom navigation controller and implement it in your storyboards.

class CustomNavigationController: UINavigationController {

 override func viewDidLoad() {
    super.viewDidLoad()
    setNavBar()
 }

 func setNavBar() {
    if #available(iOS 13.0, *) {
        let appearance = UINavigationBarAppearance()
        appearance.configureWithOpaqueBackground()
        appearance.backgroundColor = UIColor.blue
        appearance.titleTextAttributes = [.foregroundColor: UIColor.yellow]
        self.navigationBar.standardAppearance = appearance
        self.navigationBar.scrollEdgeAppearance = appearance
        self.navigationBar.compactAppearance = appearance
    } else {
        self.navigationBar.barTintColor = UIColor.blue
        self.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.yellow]
    }
  }
}

*Colors are set so you can see them clearly working.

I found it was better to set the code in ViewDidLoad rather than ViewDidAppear because my colors were not being set on the initial load, only after navigating back and reloading.

I also found that this issue might be tied to the "Bar Tint" of a NavBar. when we were first trying to resolve it, we set the "Bar Tint" to default and that seemed resolve the error too. However, it made it so we couldn't get the NavBar background color what we wanted. So in my storyboards I made sure to set this value to default just for good measure.

Hope it helps

Orangery answered 25/3, 2020 at 23:23 Comment(2)
This does work. It seems as if it is just setting the global style that doesn't work.Derris
def a bug on apple's end. can't help but break things >.<Tufted
S
3

no need for the workaround.it is a bug in Xcode Interface Builder. Apple release Update for Xcode 11.4.1

from Apple developer release notes

Interface Builder

Fixed an issue that caused some UINavigationBar appearance properties set in storyboard and XIB documents to be ignored when building with Xcode 11.4. (60883063) (FB7639654)

https://developer.apple.com/documentation/xcode_release_notes/xcode_11_4_1_release_notes

Subclinical answered 17/4, 2020 at 17:49 Comment(0)
G
0

Similar to Stu Carney's response on 3/25, I added a few more implementation details.

Create a subclass of UINavigationController. Add the following to viewWillAppear:

let isDarkMode = UserDefaults.standard.bool(forKey: "DarkMode")
let titleColor: UIColor = isDarkMode ? .white : .black
let navBarColor: UIColor = isDarkMode ? .black : .white
let tintColor: UIColor = isDarkMode ? .yellow : .red  //back button text and arrow color, as well as right bar button item

if #available(iOS 13.0, *) {
    let appearance = UINavigationBarAppearance()
    appearance.configureWithOpaqueBackground()
    appearance.backgroundColor = navBarColor
    appearance.titleTextAttributes = [.foregroundColor: titleColor]
    appearance.largeTitleTextAttributes = [.foregroundColor: titleColor]

    self.navigationBar.standardAppearance = appearance
    self.navigationBar.scrollEdgeAppearance = appearance
    self.navigationBar.compactAppearance = appearance // For iPhone small navigation bar in landscape.

    self.navigationBar.tintColor = tintColor //changes back button text and arrow color, as well as right bar button item
} else {
    self.navigationBar.barTintColor = navBarColor
    self.navigationBar.tintColor = tintColor
    self.navigationBar.titleTextAttributes = [.foregroundColor: titleColor]
    self.navigationBar.largeTitleTextAttributes = [.foregroundColor: titleColor]
}

Then override preferredStatusBarStyle:

override var preferredStatusBarStyle: UIStatusBarStyle {
    let isDarkMode = UserDefaults.standard.bool(forKey: "DarkMode")
    return isDarkMode ? .lightContent : .default
}

If you want to update the navigation bar and status bar dynamically, like from a UISwitch IBAction or selector method, add the following:

navigationController?.loadView()
navigationController?.topViewController?.setNeedsStatusBarAppearanceUpdate()

Also, be sure to set all your navigation bars and bar buttons to the default colors in IB. Xcode seems to have a bug where the the IB colors override the colors set programatically.

Giuditta answered 4/4, 2020 at 3:3 Comment(0)
T
0

In my case, after I upgraded Xcode from 11.3 to 11.4 this bug occurred. So I have to change my code to blow in order to set an image as background in the navigation bar.

if #available(iOS 13.0, *) {
    let appearance = UINavigationBarAppearance()
    appearance.configureWithOpaqueBackground()
    let backgroundImage = UIImage(named: "{NAVBAR_IMAGE_NAME}")?.resizableImage(withCapInsets: UIEdgeInsets.zero, resizingMode: .stretch)
    appearance.backgroundImage = backgroundImage
    self.navigationController?.navigationBar.compactAppearance = appearance
    self.navigationController?.navigationBar.standardAppearance = appearance
    self.navigationController?.navigationBar.scrollEdgeAppearance = appearance        
} else {
    self.navigationController?.navigationBar.barTintColor = Utils.themeColor
    let backgroundImage = UIImage(named: "{NAVBAR_IMAGE_NAME}")?.resizableImage(withCapInsets: UIEdgeInsets.zero, resizingMode: .stretch)
    self.navigationController?.navigationBar.setBackgroundImage(backgroundImage, for: .default)
    self.navigationController?.navigationBar.shadowImage = UIImage()
}
Tovatovar answered 21/4, 2020 at 6:33 Comment(0)
C
0

I had the same issue and was wondering that coding is not the solution. There MUST be a way. And found out that checking any option under Navigation bar -> Appearances in storyboard attribute inspector makes the title go black. So uncheck all of them. But not sure how I can have scroll Edge option on to color the status bar as well and still get the title colored.

Coan answered 20/8, 2022 at 12:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.