I have problem with changing navigation bar color in iOS 15.
In AppDelegate I'm setting UINavigationBarAppearence like this:
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.shadowImage = UIImage()
appearance.shadowColor = .clear
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
In my application, I need to change navigation bar color in multiple places in multiple colors.
Previously, just setting self.navigationController?.navigationBar.barTintColor = .yellow
did the trick but not anymore. Every time when I need to change navigation bar color, do I need to change whole UINavigationBarAppearence class attributes? If yes, it seems like a bit overload. But I cannot find better solution.
Others methods like
self.navigationItem.setHidesBackButton(true, animated: true)
dont work anymore too. Instead
self.navigationController?.navigationBar.topItem?.setHidesBackButton(true, animated: true)
only works. All these change just seems very confusing.
Related
I am really struggling figuring out why there's a part on top of the navigation bar that has a different color than the navigation bar.
I have set the navigation like this:
navigationController?.navigationBar.tintColor = .white
navigationController?.navigationBar.backgroundColor = .primaryBlack
navigationController?.setNavigationBarHidden(false, animated: true)
And for some reason only one part is with that color but not everything. In some other parts that part is completely transparent making it look really odd.
I encountered this issue when ever my navigation bar is using large titles and push a view controller onto the navigation stack of the navigation controller, this gap seems to be at the top:
There seems to be some gap created for some reason and the large title navigation bar starts under the status bar.
The reason I understand as per the documentation is that the base view goes under the UINavigationBar and when this view is scrolled, the UINavigationBar needs to transform.
When a navigation controller contains a navigation bar and a scroll
view, part of the scroll view’s content appears underneath the
navigation bar. If the edge of the scrolled content reaches that bar,
UIKit applies the appearance settings in this property.
Simplest thing I do is to make the underlying view the same color as the navigation bar background in the view controller and keep the result of your code the same:
// Same as your code, only changed background to blue
navigationController?.navigationBar.tintColor = .white
navigationController?.navigationBar.backgroundColor = .blue
navigationController?.setNavigationBarHidden(false, animated: true)
// What I added
view.backgroundColor = .blue
This gives me:
Update using UINavigationBarAppearance
Can you try updating using UINavigationBarAppearance
// From your code, not sure of it's purpose
navigationController?.setNavigationBarHidden(false, animated: true)
let appearance = UINavigationBarAppearance()
// Color of the nav bar background
appearance.backgroundColor = .black // primary black for you
// Color for the titles
appearance.largeTitleTextAttributes
= [NSAttributedString.Key.foregroundColor : UIColor.white]
appearance.titleTextAttributes
= [NSAttributedString.Key.foregroundColor : UIColor.white]
navigationController?.navigationBar.standardAppearance = appearance
navigationController?.navigationBar.scrollEdgeAppearance = appearance
// Color for the back button
navigationController?.navigationBar.tintColor = .white
Result:
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:
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
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
I need to increase the height of the navigation bar. For this, I have added a view (of desired height) under the navigation bar. The navigation bar is set to be translucent. So the nav bar color is rendered slightly different than the actual hex value. Now I need to match the navigation bar's color to the view below. Following is the code that I am using.
func setupNavigationBar() {
title = "Profile"
self.navigationController?.navigationBar.setBackgroundImage(UIImage(named: ""), for: .default)
self.navigationController?.navigationBar.shadowImage = UIImage(named: "")
headerView.backgroundColor = navigationController?.navigationBar.barTintColor
headerView.isOpaque = false
}
I am getting different shades as below.
How can i make the view's color to be the same as navigation bar's color? I can get near to the desired color by reducing the view's alpha but I am doubtful about that approach since there is no standard defined regarding it.
P.S. The navigation bar has to stay translucent.
You just need to set opacity of headerView to 0.85
headerView.backgroundColor = navigationController?.navigationBar.barTintColor
headerView.layer.opacity = 0.85
headerView.isOpaque = false
You can download the sample code from here:
Please ignore other unused code in the sample code.
Explanation:
When you're set navigationController style as translucent then the system automatically take layer opacity 0.85 for UINavigationController
I personally check it by iterating all subview of UINavigationController.
Set the background colour to clear for the navigation bar using :
self.navigationController?.navigationBar.backgroundColor = UIColor.clear
Hope this helps.
You can set the background color to nil and it will follow the background color.
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = nil
navigationController?.navigationBar.standardAppearance =
appearance
navigationController?.navigationBar.compactAppearance = appearance