Change current colour of NavigationBar in iOS15 - ios

I have an app with custom colour themes, and themes can implement colours in TableView Header labels and Navigation bars.
When doing this, it was working fine with iOS14. But with changes in iOS15, the navigation bar cannot change colour anymore. The transparent and scrollEdgeAppearance was handled in iOS15, but the NavBar current-colour change based on user input while the app is running(after application(didFinisLaunching) has been called) is not working.
I am using the below code to trigger when the user selects a colour:
func setNavBarColour() {
if #available(iOS 15, *) {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
appearance.backgroundColor = LangBuilds.flavColor
let proxy = UINavigationBar.appearance()
proxy.tintColor = LangBuilds.flavColor
proxy.standardAppearance = appearance
proxy.scrollEdgeAppearance = appearance
}
else {
self.navigationController?.navigationBar.barTintColor = LangBuilds.flavColor
}
self.searchController.searchBar.searchTextField.textColor = .black
self.searchController.searchBar.searchTextField.backgroundColor = .white
self.searchController.searchBar.searchTextField.autocapitalizationType = .none
changeTextHolder()
}
Thanks for your help in advance.

the NavBar current-colour change based on user input while the app is running(after application(didFinisLaunching) has been called) is not working
You cannot change a navigation bar color while that navigation bar is showing by using the appearance proxy. The appearance proxy affects only future interface elements. You need to apply your UINavigationBarAppearance to the existing navigation bar directly:
self.navigationController?.navigationBar.standardAppearance = appearance
self.navigationController?.navigationBar.scrollEdgeAppearance = appearance

Related

Swift: Status bar color different from Navigation bar color

The statusbar on the top seems to take the view background color and not the navigation bar background color. Help would be appreciated
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Hello"
self.navigationController?.navigationBar.backgroundColor = .white
self.view.backgroundColor = .blue
}
You should use UINavigationBarAppearance to customise the appearance of a navigation bar, instead of changing the background colour of the views directly.
https://developer.apple.com/documentation/uikit/uinavigationbarappearance
You can either set these directly on the UINavigationBar (standardAppearance, compactAppearance, scrollEdgeAppearance, compactScrollEdgeAppearance) or on your view controller's navigation item.
var appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = .white
self.navigationItem.standardAppearance = appearance
self.navigationItem.scrollEdgeAppearance = appearance

iOS: Can't change navigation bar color [duplicate]

This question already has answers here:
How to change navigation bar & back button colour iOS 15
(2 answers)
How to change UINavigationBar background color from the AppDelegate
(12 answers)
Closed last year.
Can't change navigation bar background color. I've tried setting colors to navigationController?.navigationBar.backgroundColor and navigationController?.navigationBar.barTintColor, such as UIColor.red in the following example, but a white UIImage appears above the navigation bar color in the view hierarchy, as shown in this image: https://imguh.com/image/CBXaj
Also tried making navigation bar translucent and opaque, to no effect. I can change the button colors and customize other elements, but not change the background color of the bar. Appreciate any help.
The following code should do the trick for you:
Background Colour
// This will change the navigation bar background color
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = UIColor.green // your colour here
navigationController?.navigationBar.standardAppearance = appearance
navigationController?.navigationBar.scrollEdgeAppearance = appearance
Place this inside the viewDidLoad() function within your ViewController
Title Colour
If you want to also change the navigation bar title appearance, then apply the following code before you set the standardAppearance and scrollEdgeAppearance:
// This will alter the navigation bar title appearance
let titleAttribute = [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 25, weight: .bold), NSAttributedString.Key.foregroundColor: UIColor.purple] //alter to fit your needs
appearance.titleTextAttributes = titleAttribute
Entire code:
// This will change the navigation bar background color
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = UIColor.green
// This will alter the navigation bar title appearance
let titleAttribute = [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 25, weight: .bold), NSAttributedString.Key.foregroundColor: UIColor.purple] //alter to fit your needs
appearance.titleTextAttributes = titleAttribute
navigationController?.navigationBar.standardAppearance = appearance
navigationController?.navigationBar.scrollEdgeAppearance = appearance
Image Example

iOS: Specify status bar text color when using UINavigationBarAppearance now barstyle is ignored

Problem
I have an app that has different colour navigation bars for different flows. Some navigation bars have a light background and require black status bar text. Others have a darker navigation bar and require white status bar text.
As part of the move to iOS15 I have updated an app I am working on to use the UINavigationBarAppearance approach to navigation bar styling.
I am able to style everything as I could before other than the status bar color.
Previously I have been using the barStyle property on navigation bar to set the status bar text color.
navigationBar.barStyle = .black
This does not appear to work when using UINavigationBarAppearance.
Sample code
Old styling approach
override func viewDidLoad() {
super.viewDidLoad()
let navigationBar = navigationController?.navigationBar
// Style using old approach
navigationBar?.barTintColor = UIColor.purple
navigationBar?.titleTextAttributes = [.foregroundColor: UIColor.white]
// Use barStyle to set status bar text color to white
// This only work when using the old styling approach
navigationBar?.barStyle = .black
}
New styling approach
override func viewDidLoad() {
super.viewDidLoad()
let navigationBar = navigationController?.navigationBar
// Style nav bar using new Appearance API
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.backgroundColor = UIColor.purple
navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
navigationBar?.standardAppearance = navBarAppearance
navigationBar?.scrollEdgeAppearance = navBarAppearance
// Use barStyle to set status bar text color to white
// This only work when using the old styling approach
navigationBar?.barStyle = .black
}
Alternatives
Force dark/light mode on the navigation bar
It is possible to make the status bar text white using the property overrideUserInterfaceStyle. To make the status bar text white, set
navigationBar.overrideUserInterfaceStyle = dark
However, this results in menus from buttons in the nav bar in dark mode too which is not what I want.
Subclass UINavigationController
I imagine I could also subclass UINavigationController and explicitly override the preferredStatusBarStyle to force black or white text.
Having to use a subclass everywhere we make new navigation controllers just to specify the status bar text color seems a bit extreme.
Anything else?
I'm not sure if there is a better approach to this?
I was able to set the status bar text white using:
navController.navigationBar.overrideUserInterfaceStyle = .dark
Note that bencallis, the creator of this question, warns that this solution "results in menus from buttons in the nav bar in dark mode too which is not what I want". I don't use menus like this so that is not a problem for me. Maybe it's not for you too.
I use both barStyle and overrideUserInterfaceStyle with UINavigationBarAppearance
// statusBarStyle is .black or .default
if case .black = statusBarStyle {
navigationController?.navigationBar.overrideUserInterfaceStyle = .dark
} else {
navigationController?.navigationBar.overrideUserInterfaceStyle = .light
}
navigationController?.navigationBar.barStyle = statusBarStyle
See how it works:

Tab & Navigation Bar changes after upgrading to XCode 13 (& iOS 15)

I have an iOS app, since upgrading to Xcode 13, I have noticed some peculiar changes to Tab and Navigation bars. In Xcode 13, there's now this black area on the tab and nav bars and on launching the app, the tab bar is now black as well as the navigation bar. Weird enough, if the view has a scroll or tableview, if I scroll up, the bottom tab bar regains its white color and if I scroll down, the navigation bar regains its white color.
N:B: I already forced light theme from iOS 13 and above:
if #available(iOS 13.0, *) {
window!.overrideUserInterfaceStyle = .light
}
Can anyone assist or point me in the right direction so as to deal with this peculiarity?
Is there a simple fix to get Storyboard to readjust or this is a case where I have to make changes to each view manually?
Example of Storyboard before upgrade:
and after:
Simulator screen before and after (respectively) upgrade:
About Navigation Bar is black, try do it:
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = .red
appearance.titleTextAttributes = [.font:
UIFont.boldSystemFont(ofSize: 20.0),
.foregroundColor: UIColor.white]
// Customizing our navigation bar
navigationController?.navigationBar.tintColor = .white
navigationController?.navigationBar.standardAppearance = appearance
navigationController?.navigationBar.scrollEdgeAppearance = appearance
I wrote a new article talking about it.
https://medium.com/#eduardosanti/uinavigationbar-is-black-on-ios-15-44e7852ea6f7
After update to XCode 13 & iOS 15 I also faced some Tab Bar issues with bar background color and items text color for different states. The way I fixed it:
if #available(iOS 15, *) {
let tabBarAppearance = UITabBarAppearance()
tabBarAppearance.backgroundColor = backgroundColor
tabBarAppearance.stackedLayoutAppearance.selected.titleTextAttributes = [.foregroundColor: selectedItemTextColor]
tabBarAppearance.stackedLayoutAppearance.normal.titleTextAttributes = [.foregroundColor: unselectedItemTextColor]
tabBar.standardAppearance = tabBarAppearance
tabBar.scrollEdgeAppearance = tabBarAppearance
} else {
UITabBarItem.appearance().setTitleTextAttributes([.foregroundColor: selectedItemTextColor], for: .selected)
UITabBarItem.appearance().setTitleTextAttributes([.foregroundColor: unselectedItemTextColor], for: .normal)
tabBar.barTintColor = backgroundColor
}
For me I had problem with both Navbar and TabBar so I applied the styles globally in the AppDelegate
func configureNavigationBarAppearance() {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = .white
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
}
func configureTabBarAppearance() {
let appearance = UITabBarAppearance()
appearance.backgroundColor = .white
UITabBar.appearance().standardAppearance = appearance
UITabBar.appearance().scrollEdgeAppearance = appearance
}
You can do this in storyboards by selecting the Tab Bar and in attributes inspector selecting both standard and scroll edge appearance, setting both of their settings as with iOS 13 and for custom fonts or colors you need to change Standard Layout Appearances Stacked to Custom and set the attributes.
For Navigation Bar you set Standard and Scroll Edge Appearances similarly in Attributes Inspector but this has been mentioned elsewhere in stack overflow.
in XCode13.0 and iOS 15.0 tabbar and navigation bar transaparent issue programatically resolved 100%
For Tabbar
if #available(iOS 15, *) {
let appearance = UITabBarAppearance()
appearance.configureWithOpaqueBackground()
UITabBar.appearance().standardAppearance = appearance
UITabBar.appearance().scrollEdgeAppearance = appearance
}
For NavigationBar
if #available(iOS 15, *) {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
}
first of all the problem is cause by unchecking translucent
I fixed it by choosing navigation bar appearance from attributes inspector scroll edge
it will fix it see this screen shot please
My problem is solved by following, replace the color on right you want for navigation bar
navigationController?.navigationBar.backgroundColor = .lightGray

Why is UISearchController changing the navigation bar colors?

I have tested this on a sample project with 2 view controllers defined in the storyboard using Xcode 11 (iOS 13). The "presenting" view controller is embedded in a navigation controller and has the navigation bar colors set in the viewWillAppear.
The "search" view controller adds a UISearchController in the viewDidLoad and is pushed by the presenting view controller (NOT modal).
With just this setup when the search view controller is displayed the navigation bar has the blue background and red tint color as expected. However when scrolling down and the search bar is displayed the background color of the navigation bar is lost (or changed to what appears to be the default iOS grey / translucent). However if you scroll back up (hide the search bar) or focus on the search bar text field the navigation bar color returns!
Also if you focus on the search bar text field and then cancel (by tapping the Cancel button) the tint color of the navigation bar reverts from red to the default iOS blue as can be noticed by the back bar item.
Any suggestions on resolving this issue?
I have set the navigation bar colors in the viewWillAppear of the search controller too which didn't change this behaviour.
I set isTranslucent to true for the navigation bar in the search controller which seemed to prevent the reverting of the background color but it did not change the reverting of the tint color on cancel.
Presenting View Controller
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.navigationBar.barTintColor = .blue
navigationController?.navigationBar.tintColor = .red
}
Search View Controller
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Search VC"
searchController.dimsBackgroundDuringPresentation = false
searchController.obscuresBackgroundDuringPresentation = false
navigationItem.searchController = searchController
definesPresentationContext = true
}
EDIT
Setting the scrollEdgeAppearance, backButtonAppearance and buttonAppearance as suggested works a treat except for system bar buttons that default to the iOS blue. This can be resolved by setting the UINavigationBar.tintColor but neither that resolves the back button chevron color defaulting on cancel of the search.
if #available(iOS 13.0, *) {
let buttonAppearance = UIBarButtonItemAppearance()
buttonAppearance.configureWithDefault(for: .plain)
buttonAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.red]
let navigationBarAppearance = UINavigationBarAppearance()
navigationBarAppearance.configureWithOpaqueBackground()
navigationBarAppearance.backgroundColor = .blue
navigationBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.red]
navigationBarAppearance.backButtonAppearance = buttonAppearance
navigationBarAppearance.buttonAppearance = buttonAppearance
navigationBarAppearance.doneButtonAppearance = buttonAppearance
navigationController?.navigationBar.scrollEdgeAppearance = navigationBarAppearance
navigationController?.navigationBar.compactAppearance = navigationBarAppearance
navigationController?.navigationBar.standardAppearance = navigationBarAppearance
} else {
navigationController?.navigationBar.barTintColor = .blue
navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.red]
navigationController?.navigationBar.tintColor = .red
}
However when scrolling down and the search bar is displayed the background color of the navigation bar is lost
All of that is normal. New in iOS 13, the expanded nav bar (displaying search bar, large title, etc.) has different appearance from the normal nav bar. Your settings applied only to the normal nav bar because you didn't make them the iOS 13 way. If you want the expanded nav bar to look like the normal nav bar, you have to set its appearance separately and explicitly.
To do so, you need to set the navigation bar's scrollEdgeAppearance. Investigate classes UIBarAppearance, UINavigationBarAppearance, and UIBarButtonItemAppearance (you will need to set the backButtonAppearance explicitly).

Resources