When I add a UISearchController to a UINavigationItem from an UINavigationController; it becomes white when the view loads and changes to the color specified when the user clicks on the search bar. This happened since ios 13.1. This video shows the behaviour:
https://imgur.com/wn5zbnJ
My code consists of a simple storyboard with a NavigationController + a TableViewController, and the NavigationController has a color assigned to it:
The ViewController consists of the following code:
class ViewController: UITableViewController {
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
searchController.hidesNavigationBarDuringPresentation = false
searchController.obscuresBackgroundDuringPresentation = false
navigationItem.searchController = searchController
}
}
I also added these keys to the info.plist file to force the app into light-mode, but if I remove these the same behaviour is still present:
<key>UIUserInterfaceStyle</key>
<string>Light</string>
This was tested on an iPhone XS Max, running iOS 13.1 beta 1. Is this expected behaviour or a bug which needs to be fixed?
It looks like it is required to use the new UINavigationBarAppearance on iOS 13. Try to add this to your viewDidLoad:
let appearance = UINavigationBarAppearance()
appearance.backgroundColor = .systemRed
appearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor : UIColor.white]
navigationItem.standardAppearance = appearance
navigationItem.scrollEdgeAppearance = appearance
You will probably also want to set the searchField backgroundColor:
let searchField = searchController.searchBar.searchTextField
searchField.backgroundColor = .systemBackground
This appears to be a bug in iOS 13.1. Specifically, there is a new iOS 13 specific appearance (UINavigationBarAppearance) for navigation bars which specifies the appearance when the scroll view is scrolled to the top, along with the default state. Normally changes like this only go into effect when the app is built with the corresponding SDK (iOS 13.1). However, there seems to be a bug where the behavior also occurs when an app is built using the iOS 12 SDK.
See: https://developer.apple.com/documentation/uikit/uinavigationbarappearance
Update:
There is a workaround here: https://itnext.io/fixing-issues-caused-by-future-sdks-ae0896384abf
Essentially, if your app is running on a device running iOS 13, it's possible to create instances of the new classes via NSClassFromString() in swift, then use a bit of objective-c runtime magic to configure the navigation bar.
What you want was not clear in your question. If you want, however, add searchbar into navigationBar and with a specific color this might help you.
The process of placing seachbar into navigation bar:
let searchController = UISearchController(searchResultsController: nil)
navigationItem.searchController = searchController
You can add whatever controller you want into 'searchResultsController' value.
If you want to set background color into a specific color, you can change the bar tint from Storyborad -> navigationbar -> navigation bar attiribute inspection.
Also, this below code for the AppDelegate.swift file will do the same. 'tintcolor' and 'titletextcolor' is commented
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let navigationBarAppearace = UINavigationBar.appearance()
navigationBarAppearace.barTintColor = UIColor.blue
// navigationBarAppearace.tintColor = UIColor.red
//navigationBarAppearace.titleTextAttributes = [.foregroundColor: UIColor.red]
return true
}
I'm experiencing same issue, and already opened a radar to Apple.
Even though, if you set the backgroundColor to the appearance of the UINavigationBar, then the navigation bar instead of becoming transparent when pulling down and showing the search bar becomes that color, but then the status bar still remains white.
UINavigationBar.appearance().tintColor = .white
UINavigationBar.appearance().barTintColor = .blue
UINavigationBar.appearance().titleTextAttributes = [NSAttributedString.Key.foregroundColor : UIColor.white]
UINavigationBar.appearance().backgroundColor = .red
Here is some code that tries to mitigate that behaviour, but I'm open to hear for the status bar thing
Related
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 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).
Code:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
UINavigationBar.appearance().barTintColor = .red
return true
}
if prefersLargetitles is false then there is no problem.
But with prefersLargeTitles = true, the color doesn't change.
This used to work with iOS 12. But since iOS 13 this is not working. Can anybody help on how to customise navigation bars in iOS 13
There are some changes regarding navigation bar appearance in iOS 13, by default navigation bar becomes transparent if associates view controller has scrollable content.
In this case, you should create an UINavigationBarAppearance object and assign it to compactAppearance and scrollEdgeAppearance. You can change properties of UINavigationBarAppearance object as well.
if #available(iOS 13.0, *) {
let appearance = UINavigationBarAppearance()
appearance.backgroundColor = .purple
UINavigationBar.appearance().compactAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
} else {
UINavigationBar.appearance().barTintColor = .purple
}
You can find more detail at here & iOS13release_notes
For some reason I can't figure out why I'm not able to change the tintColor of my navigation bar buttons in my app and I don't know how to figure out why. Can you recommend how I can debug this issue?
I am adding this to the viewDidLoad of my view controller:
UINavigationBar.appearance().tintColor = .green
However, nothing changes and the back button and Aa bar button stay the default grey color.
The navigation + status bars are translucent and sit on top of the background color of the viewcontroller through out the app.
I am able to change the barbutton to .green in a test app where I do the exact same (add it to ViewDidLoad of a vc, make sure that the barbutton images assets are set to Template so they'll take on the color I set). But for whatever reason, that same thing won't change in my app prototype.
Are there are any common reasons for this that I might not know of?
Added: the bar button was added via storyboard only.
And here is the code attempt to change its color via the viewDidLoad of 1 viewcontroller:
Class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
UINavigationBar.appearance().tintColor = .green
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.isTranslucent = true
}
}
If you want to use the global appearance() proxy, then you can't do it in your view controller.
If you want to change the tintColor in viewDidLoad of your view controller then you have to set it on your controller's navigationController instance directly:
navigationController?.navigationBar.tintColor = .green
To use the appearance() proxy, and set a global tintColor for navigation bars, you'll have to do it before your navigation controller is initialized.
For example, it will work if you do it in your app delegate's application(_:didFinishLaunchingWithOptions:):
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UINavigationBar.appearance().tintColor = .green
return true
}
See the UIAppearance documentation for details of why this is:
https://developer.apple.com/documentation/uikit/uiappearance
"iOS applies appearance changes when a view enters a window, it doesn’t change the appearance of a view that’s already in a window. To change the appearance of a view that’s currently in a window, remove the view from the view hierarchy and then put it back."
Navigation Bar color
To change the background color of the navigation bar, use the below code
navigationController?.navigationBar.barTintColor = .green
Change .green with your desired color.
Navigation Bar Text Color
navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.green]
Change .green with your desired color.
UINavigationBar.appearance().barTintColor = UIColor(hex:"YourColorcode")
UINavigationBar.appearance().tintColor = UIColor.white
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white,
NSFontAttributeName: UIFont(name:"AvenirNext-Medium", size:19.0)]
UIBarButtonItem.appearance().setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.white,
NSFontAttributeName: "YourFontName"], for: UIControlState.normal)