I have a view controller with a navigation bar with a large title. When I push the controller, only on iOS 13 is a line visible under the Navigation bar. How can I solve it?
I have already tried several solutions on Stack but they have not worked like:
let navigationBar = navigationController?.navigationBar
let navigationBarAppearence = UINavigationBarAppearance()
navigationBarAppearence.shadowColor = .clear
navigationBar?.scrollEdgeAppearance = navigationBarAppearence
With this snippet, even if I change the "clear color" with red color it is visible only in the first controller, in the pushed controller it is always gray.
How can I solve it?
Edit
I've solved with:
if #available(iOS 13.0, *) {
let appearance = UINavigationBarAppearance()
appearance.shadowColor = nil
navigationController?.navigationBar.standardAppearance = appearance
}
import UIKit
public protocol HideableHairlineHelper {
func hideHairline()
func showHairline()
}
extension HideableHairlineHelper where Self: UIViewController {
public func hideHairline() {
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.toolbar.setShadowImage(UIImage(), forToolbarPosition: .any)
}
public func showHairline() {
self.navigationController?.navigationBar.shadowImage = nil
}
}
I've tried the above-suggested ones and failed to remove the navigation separator line. Eventually, I've figured it out that to use TransparentBackground
The trick is to initialize UINavigationBarAppearance with TransparentBackground. Then you could easily remove the horizontal line of the navigation bar.
let appearance = UINavigationBarAppearance()
appearance.configureWithTransparentBackground()
appearance.backgroundColor = UIColor.green // Required background color
Then add the appearance changes to the navigation item as the apple suggested.
self.navigationItem.standardAppearance = appearance
self.navigationItem.scrollEdgeAppearance = appearance
self.navigationItem.compactAppearance = appearance
This is my NavBar template I use on my controllers, there's no line.
navigationController?.setNavigationBarHidden(false, animated: false)
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
navigationController?.navigationBar.shadowImage = UIImage()
navigationController?.navigationBar.isTranslucent = true
let titleAttributes =
[
NSAttributedString.Key.font: UIFont.systemFont(ofSize: 18),
NSAttributedString.Key.foregroundColor: UIColor.red,
]
self.navigationController?.navigationBar.titleTextAttributes = titleAttributes
I obviously change the font size and colour around but that's the basic function I put for each controller to get it clear(translucent).
Related
I'm trying to customize a UITabBar using Swift in Xcode, however I can't figure our how to set the color of the unselected items using the menu on the right side of the window. I've tried the following approaches:
I made a custom class for the TabBarController and implemented it as follows:
class CustomTabBarController : UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
// set unselectedItemTintColor for UITabBar contained in this Controller...
self.tabBar.unselectedItemTintColor = UIColor.white
}
}
When method 1 didn't work, I updated the custom class for the TabBarController with the following implementation...
class CustomTabBarController : UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
// try setting unselected item tint color using new Appearance API...
let appearance = UITabBarAppearance()
appearance.backgroundColor = UIColor.white
appearance.shadowImage = UIImage()
appearance.shadowColor = UIColor.white
appearance.stackedLayoutAppearance.normal.iconColor = UIColor.white
appearance.stackedLayoutAppearance.normal.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
appearance.stackedLayoutAppearance.normal.badgeBackgroundColor = UIColor.white
self.tabBar.standardAppearance = appearance
}
}
Neither of these implemented approaches worked, so I'm trying to figure out what approach/implementation will work. I'm using Xcode version 13.2.1 and Swift version 5.5.2 on an iPhone 11 Pro Max device emulator running iOS 15.2.
Thank you in advance! I really appreciate any suggestions I could get for solving this issue.
I just face the same problem and find a solution for this.
Put this code in your UITabBarController class
if #available(iOS 15, *) {
let tabBarAppearance = UITabBarAppearance()
tabBarAppearance.backgroundColor = .white
tabBarAppearance.stackedLayoutAppearance.selected.titleTextAttributes = [.foregroundColor: UIColor.red]
tabBarAppearance.stackedLayoutAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.black]
tabBarAppearance.stackedLayoutAppearance.normal.iconColor = UIColor.black
tabBarAppearance.stackedLayoutAppearance.selected.iconColor = UIColor.red
tabBarView.standardAppearance = tabBarAppearance
tabBarView.scrollEdgeAppearance = tabBarAppearance
}
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.
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?
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];
}
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.
Apple finally fixed it in version 11.4.1
https://developer.apple.com/documentation/xcode_release_notes/xcode_11_4_1_release_notes
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
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
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.
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()
}
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.
In iOS 13, they have changed the way that the nav bar colors operate. Now they use UINavigationBarAppearance along with UIBarButtonItemAppearance to customize the nav bar, along with standardAppearance & scrollEdgeAppearance.
I'm looking for a way to have different nav bar tint colors for standardAppearance & scrollEdgeAppearance. Or the ability to change bar button icon colors for each appearance.
//set the standard nav bar appearance
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
navBarAppearance.backgroundColor = UIColor.mainAppColorForNavBar
//set bar button appearance
let buttonAppearance = UIBarButtonItemAppearance()
buttonAppearance.normal.titleTextAttributes = [.foregroundColor : UIColor.white]
navBarAppearance.buttonAppearance = buttonAppearance
UINavigationBar.appearance(whenContainedInInstancesOf: [UINavigationController.self]).standardAppearance = navBarAppearance
//set the scroll edge nav bar appearance
let scrollNavBarAppearance = UINavigationBarAppearance()
scrollNavBarAppearance.configureWithOpaqueBackground()
scrollNavBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.label]
scrollNavBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.label]
//set bar button appearance
let scrollButtonAppearance = UIBarButtonItemAppearance()
scrollButtonAppearance.normal.titleTextAttributes = [.foregroundColor : UIColor.label]
scrollNavBarAppearance.buttonAppearance = scrollButtonAppearance
UINavigationBar.appearance(whenContainedInInstancesOf: [UINavigationController.self]).scrollEdgeAppearance = scrollNavBarAppearance
This will set the nav bar tint color but does not distinguish between standardAppearance & scrollEdgeAppearance.
UINavigationBar.appearance().tintColor = UIColor.white
currently in scrollEdgeAppearance (looks the way I want, no changes needed)
currently in standardAppearance (the button is lost because it's the same color as the background, I want to change the icon color to white in standardAppearance )
Any help is appreciated.
Thanks,
I ran into a similar issue for the back button and solved it with setting an image with a different rendering mode for each appearance. This avoids a tintColor being applied.
// demo image
let image = UIImage(systemName: "ellipsis.circle")!
// image with .alwaysOriginal rendering mode to avoid tintColor application
let imageForNavBarAppearance = image
.withTintColor(.black)
.withRenderingMode(.alwaysOriginal)
let imageForScrollNavBarAppearance = image
.withTintColor(.green)
.withRenderingMode(.alwaysOriginal)
// your UINavigationBarAppearance instances
navBarAppearance.setBackIndicatorImage(imageForNavBarAppearance, transitionMaskImage: imageForNavBarAppearance)
scrollNavBarAppearance.setBackIndicatorImage(imageForScrollNavBarAppearance, transitionMaskImage: imageForScrollNavBarAppearance)
This solves it for back buttons only.
There are two other options to set background images for bar item appearances.
UINavigationBarAppearance.buttonAppearance
The appearance configuration with the background image would be applied to all bar items.
This should be fine, since you only have one bar item.
UINavigationBarAppearance.doneButtonAppearance
If you'd create a done-style bar item for your top-right "+" symbol, this appearance configuration should apply.
let ap = UIBarButtonItemAppearance()
ap.normal.backgroundImage = image.withTintColor(.black).withRenderingMode(.alwaysOriginal)
let scrollAp = UIBarButtonItemAppearance()
scrollAp.normal.backgroundImage = image.withTintColor(.green).withRenderingMode(.alwaysOriginal)
// apply to all bar items
navBarAppearance.buttonAppearance = ap
scrollNavBarAppearance.buttonAppearance = scrollAp
// or apply to done buttons
navBarAppearance.doneButtonAppearance = ap
scrollNavBarAppearance.doneButtonAppearance = scrollAp
After playing around with iOS 13 UINavigationBarAppearance , UIBarButtonItemAppearance etc. I realised that setting a color to navigationBar.tintColor directly apparenty overrides any UIBarButtonItemAppearance configurations.
So here is my workaround:
Given that your UIViewController most likely uses an UICollectionView, UITableView, UIScrollView use it’s UIScrollViewDelegate to get scroll updates. Also possible via KVO:
private func observeScrollView() {
self.observer = scrollView.observe(
\UIScrollView.contentOffset,
options: .new
) { [weak self] scrollView, change in
guard let offsetY = change.newValue?.y else { return }
self?.handleScroll(offsetY)
}
}
Now you need to calculate if your LargeTitles are still showing. You can use navigationController?.navigationBar.frame.maxY to access it’s height.
private func handleScroll(_ offsetY: CGFloat) {
let offsetY = -offsetY
let threshold: CGFloat = navigationController?.navigationBar.frame.maxY ?? 88
let largeTitlesVisible = offsetY > threshold
self.largeTitlesVisible = largeTitlesVisible
}
Use property observers to catch toggles.
private var largeTitlesVisible: Bool = true {
didSet {
if oldValue != largeTitlesVisible {
updateNavbar(tranparent: largeTitlesVisible)
}
}
}
Now actually change the navbars appearance:
func updateNavbar(transparent: Bool) {
// overrides UIBarButtonItemAppearance, UINavigationBarAppearance configurations ...
navigationController.navigationBar.tintColor = transparent ? UIColor.clear : UIColor.systemGreen
}
I have used largeNavigationBar and it's ok until i swipe back to root view controller and large navigation gets clear color in a nasty way. Here's the code:
func largeNavigationTitle() {
self.navigationController?.view.backgroundColor = VVUtility.navigationBarColor()
let productTitle = request?.product?.name
self.navigationItem.title = "\(productTitle ?? " ")".localized()
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor : UIColor.white, NSAttributedStringKey.font : VVUtility.normalFontWithPlusSize(increaseSize: -2.0)]
if #available(iOS 11.0, *) {
self.navigationController?.navigationBar.prefersLargeTitles = true
self.navigationController?.navigationBar.backgroundColor = VVUtility.splashBackGroundColor()
self.navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedStringKey.foregroundColor : UIColor.white, NSAttributedStringKey.font : VVUtility.normalFontWithPlusSize(increaseSize: 0.0)]
} else {
// Fallback on earlier versions
}
}
I've recalled largeNavigationTitle() in both viewWillAppear and viewDidLoad
UPDATE
Here is screenshot of two states:
Before swiping: imgur.com/a/ZcSOrov
When swiping: imgur.com/a/DYeeot8
Try this. It should set your root View controller's navigationBar's colour to the one you wanted:
func largeNavigationTitle() {
self.navigationController?.view.backgroundColor = VVUtility.navigationBarColor()
//add the two lines below
self.navigationController?.navigationBar.barTintColor = VVUtility.navigationBarColor()
self.navigationController?.navigationBar.isTranslucent = false
let productTitle = request?.product?.name
self.navigationItem.title = "\(productTitle ?? " ")".localized()
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor : UIColor.white, NSAttributedStringKey.font : VVUtility.normalFontWithPlusSize(increaseSize: -2.0)]
if #available(iOS 11.0, *) {
self.navigationController?.navigationBar.prefersLargeTitles = true
self.navigationController?.navigationBar.backgroundColor = VVUtility.splashBackGroundColor()
self.navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedStringKey.foregroundColor : UIColor.white, NSAttributedStringKey.font : VVUtility.normalFontWithPlusSize(increaseSize: 0.0)]
} else {
// Fallback on earlier versions
}
}
Did you try this in your code ?
self.navigationController.navigationBar.translucent = NO;
This is actually your navigation bar changing back to the small bar mode on the bottom controller.
This is because your navigation bar is not translucent. This causes (by default) the content controller to stop at the bottom of the navigation bar. So when the navigation bar becomes small again, there is no content between its new, shorter bottom and the top of the view controller.
Your hierarchy will look like this:
Now there's a property on UIViewController that defaults to false. You can use it to specify that you want your controller's view to extend under the non-translucent bar:
extendedLayoutIncludesOpaqueBars = true
This instantly makes the hierarchy now appear as:
Now you should no longer get the gap - but you might have issues with UI elements going under the bar. You can handle that by using Safe area insets and tweaking your layout as needed, using edgesForExtendedLayout may also help depending on your layout.
TL;DR Use extendedLayoutIncludesOpaqueBars = true
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 + " "
I try something that works on my UIViewController (both global & current navigation bar appearance):
UINavigationBarAppearance* appearance = [[UINavigationBarAppearance alloc] init];
appearance.backgroundColor = bgColor;
appearance.titleTextAttributes = #{NSForegroundColorAttributeName : [UIColor whiteColor]};
[UINavigationBar appearance].standardAppearance = appearance;
[UINavigationBar appearance].scrollEdgeAppearance = appearance;
self.navigationController.navigationBar.standardAppearance = appearance;
self.navigationController.navigationBar.scrollEdgeAppearance = appearance;