I'm trying to set the UINavigationBar appearance (tintColor
, barTintColor
etc) between screens, but at the moment in iOS 11 most of this seems to be completely ignored or doesn't behave as expected. The bar appearance changes inside a single navigation controller, when a view is pushed or popped. I have two functions, which I call in viewWillAppear
.
I need to be able to set the title colour, the left and right bar button item colour, back button colour and bar tint colour.
I'm trying to get just the colours working at the moment, so I tried this, but no joy.
public func setDarkHeaderStyle() {
UIApplication.shared.statusBarStyle = .lightContent
UINavigationBar.appearance().tintColor = UIColor.white
UINavigationBar.appearance().barTintColor = Colours.secondaryNavy
UINavigationBar.appearance().isTranslucent = false
}
public func setLightHeaderStyle() {
UIApplication.shared.statusBarStyle = .default
UINavigationBar.appearance().tintColor = Colours.primaryNavy
UINavigationBar.appearance().barTintColor = UIColor.white
UINavigationBar.appearance().isTranslucent = false
}
If I instead use the navigation controller to set the colours, it does work for the bar tint, the UIBarButtonItem
and the back button, but the title is incorrect.
public func setDarkHeaderStyle() {
UIApplication.shared.statusBarStyle = .lightContent
navigationController?.navigationBar.tintColor = UIColor.white
navigationController?.navigationBar.barTintColor = Colours.secondaryNavy
navigationController?.navigationBar.isTranslucent = false
}
public func setLightHeaderStyle() {
UIApplication.shared.statusBarStyle = .default
navigationController?.navigationBar.tintColor = Colours.primaryNavy
navigationController?.navigationBar.barTintColor = UIColor.white
navigationController?.navigationBar.isTranslucent = false
}
So I manually set the title text attributes with the following:
public func setDarkHeaderStyle() {
UIApplication.shared.statusBarStyle = .lightContent
navigationController?.navigationBar.titleTextAttributes = [
NSAttributedStringKey.font: UIFont(name: Fonts.fontRegularName, size: 16)!,
NSAttributedStringKey.kern: 0.2,
NSAttributedStringKey.foregroundColor: UIColor.white
]
navigationController?.navigationBar.tintColor = UIColor.white
navigationController?.navigationBar.barTintColor = Colours.secondaryNavy
navigationController?.navigationBar.isTranslucent = false
}
public func setLightHeaderStyle() {
UIApplication.shared.statusBarStyle = .default
navigationController?.navigationBar.titleTextAttributes = [
NSAttributedStringKey.font: UIFont(name: Fonts.fontRegularName, size: 16)!,
NSAttributedStringKey.kern: 0.2,
NSAttributedStringKey.foregroundColor: Colours.primaryNavy
]
navigationController?.navigationBar.tintColor = Colours.primaryNavy
navigationController?.navigationBar.barTintColor = UIColor.white
navigationController?.navigationBar.isTranslucent = false
}
This seems to work, except when you pop back to the root view the title colour isn't set:
I guess I have two questions:
Why doesn't UINavigationBar.appearance()
work?
How can I get this working reliably?
I think this is a bug. UIBarNavigationItem
for some reason seems to ignore your changes on its title attributes and tint color unless the text of your title changes. This is a weird behaviour and you might consider reporting it. A workaround could be to toggle an empty space suffix to your title:
// Hack!!! adds and removes an empty space to the title to
// force the bar item reset title attributes.
let title: String = barItem.title ?? ""
barItem.title = title.hasSuffix(" ") ? String(title.dropLast()) : title + " "