I'm applying the new appearance API for NavigationBar and I'm struggling with the status bar content (text). On Info.plist I forced to use the light mode because most of the app is white, but in one of my viewControllers, the navigation bar is dark blue (almost black) so the content within this bar needs to be white.
I used to use navigationBar.barStyle = .black on versions up to iOS 12.4, but for iOS 13 and above it doesn't work anymore. Follow the code I've tried and failed.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let navController = self.navigationController {
let navBarAppearance = navController.navigationBar.standardAppearance.copy()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.shadowImage = UIImage()
navBarAppearance.backgroundColor = LayoutBootstrap.colors.primary.solid // Dark blue
navController.navigationBar.standardAppearance = navBarAppearance
navController.navigationBar.barStyle = .black
}
}
Status bar content is black
PS: On didFinishLaunchingWithOptions I already called a default configuration appearance for NavigationBar and Items
Do you guys have any suggestion?
Thanks in advance.
You need to set the status bar style as well
UIApplication.shared.statusBarStyle = .lightContent
Related
Recently I updated my Xcode to 13 and after that, I am facing some issues with the navigation bar and Status bar. I am using the tab bar in my view controller. After updating the Xcode, according to the version, I added some code related to the navigation bar.
if #available(iOS 15.0, *) {
tableView.sectionHeaderTopPadding = 0
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = UIColor(red: 58/255,green: 24/255, blue: 93/255, alpha: 1.0)
appearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
// Customizing our navigation bar
navigationController?.navigationBar.tintColor = .white
navigationController?.navigationBar.barTintColor = .white
navigationController?.navigationBar.standardAppearance = appearance
navigationController?.navigationBar.scrollEdgeAppearance = appearance
}
Everything is working when I first opened the app. When I click on the other tab and then this tab. The status bar text color is changing.
I tried different ways to set the status bar text color. But nothing worked for me.
Use this function:
extension YourViewController {
override var preferredStatusBarStyle: UIStatusBarStyle {
.lightContent
}
}
If you just want to set to white colour you status bar in the entire project you can easily do it by adding the following keys into your project.plist file:
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
So, what does these keys do... You are just defining that you status bar colour will not be controlled by the any view controller and that the default colour will be "light theme" that is pretty much the white colour that you want in this case...
this would be the best approach if you do not intent to update the status bar colour all over the place.
this was tested and is working as expected on Xcode 13 and iOS [13.x,14.x,15.x]
If you want to update to customise or update the colours for the navigation bar you would should be able to do with an extension like this one bellow, just few examples but you guys should get what I mean:
extension UINavigationBar {
func clearBackground() {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithTransparentBackground()
navBarAppearance.shadowColor = UIColor.clear
navBarAppearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
self.standardAppearance = navBarAppearance
self.scrollEdgeAppearance = navBarAppearance
}
func blackColor() {
// Create an Appearance and customise as you wish.
// in this case just a black background with titles in white.
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.shadowColor = UIColor.black
navBarAppearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
self.standardAppearance = navBarAppearance
self.scrollEdgeAppearance = navBarAppearance
}
}
with this code you should be able to easy update on any view controller by just calling something like:
override func viewDidLoad() {
super.viewDidLoad()
// set the navigation bar color as transparent
self.navigationController?.navigationBar.clearBackground()
}
I am trying to change the background color of the navigation bar to black but without success. I have checked the answer to this related question but none of the solutions have worked. This is what I have tried:
navigationController?.navigationBar.backgroundColor = UIColor.black
UINavigationBar.appearance().backgroundColor = UIColor.black
You can also change the navigation bar color for a specific view controller, this way:
extension UIViewController {
func setCustomNavigationColor(color: UIColor = .black, isTranslucent: Bool = false ){
self.navigationController?.navigationBar.barTintColor = color
self.navigationController?.navigationBar.isTranslucent = isTranslucent
}
}
call this from viewDidLoad()
setCustomNavigationColor()
Try this:
UINavigationBar.appearance().barTintColor = .black
UINavigationBar.appearance().isTranslucent = false
Note: This changes the bar colour for the entire app.
I have some problems with my tabbed view when I set isTranslucent to false in combination with a NavigationView.
Does anyone know how to fix this? The problem is shown in the attached image.
I need translucent set to false otherwise I can't get the dark color.
You can set backgroundColor. Don't set isTranslucent to false or it will create these artefacts you mentioned.
UITabBar.appearance().backgroundColor = .black
UINavigationBar.appearance().backgroundColor = .black
It becomes much darker. It isn't completely opaque though.
Edit: Just watched Modernizing Your UI for iOS 13 This is the way to do it :
The TabView and NavigationView are actually UIHostedController for the legacy UITabBarController and UINavigationController:
let appearance = UITabBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.titleTextAttributes = [.foregroundColor: UIColor.white]
appearance.largeTitleTextAttributes = [.foregroundColor: UIColor .white]
Then set the appearance on the various type of appearance.
tabBar.standardAppearance = appearance
2nd Edit:
extension UINavigationController {
override open func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
navigationBar.standardAppearance = appearance
navigationBar.compactAppearance = appearance
navigationBar.scrollEdgeAppearance = appearance
}
}
extension UITabBarController {
override open func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let appearance = UITabBarAppearance()
appearance.configureWithOpaqueBackground()
tabBar.standardAppearance = appearance
}
}
There should be a cleaner way to get to both tabBar and navBar.
Reference: https://developer.apple.com/videos/play/wwdc2019/224/
I was using UIKit with SwiftUI. My Tab bar was creating in storyboard but the view for which I was getting extra bottom space was a swiftui view as you mentioned. I tried all above solution but Nothing worked for me.
I am using Xcode 12.4 for development. My solution is to mark Translucent to true in storyboard and Bottom extra gray bar was gone.
Just customize it in an extension like this:
extension UITabBarController {
override open func viewDidLoad() {
super.viewDidLoad()
let appearance = UITabBarAppearance()
appearance.backgroundColor = .black
tabBar.standardAppearance = appearance
}
}
Pay attention that the overridden function must be viewDidLoad(). At least it doesn't work for me when it is a viewDidAppear(:) function.
It's easier than all that, just delete the next line:
UITabBar.appearance().isTranslucent = false
I am presenting a UIImagePickerController to pick an image. My code is as simple as:
private lazy var imagePicker: UIImagePickerController = {
let picker = UIImagePickerController()
picker.navigationBar.isTranslucent = false
return picker
}()
func presentPicker() {
imagePicker.sourceType = .photoLibrary
imagePicker.modalPresentationStyle = .fullScreen
present(self.imagePicker, animated: true, completion: nil)
}
I am setting picker.navigationBar.isTranslucent = false to have an opaque navigation bar in the picker controller. Unfortunately this doesn't work on iOS 13 and the navigation & status bars are transparent.
Partial solution:
private func setOpaqueNavigationiOS13() {
UINavigationBar.appearance().backgroundColor = .white
}
private func resetNavigationiOS13() {
UINavigationBar.appearance().backgroundColor = .clear
}
I call the above functions to make the navigation bar opaque and to reset it when dismissing the picker. This makes the navigation bar opaque but the status bar is transparent. I can implement a hack to make the status bar opaque as well but I guess there should be a simpler solution.
EDIT:
I've also tried setting the navigation bar's appearance by the new UINavigationBarAppearance:
if #available(iOS 13.0, *) {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = .white
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().compactAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
}
Or:
if #available(iOS 13.0, *) {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = .white
imagePicker.navigationBar.standardAppearance = appearance
imagePicker.navigationBar.compactAppearance = appearance
imagePicker.navigationBar.scrollEdgeAppearance = appearance
}
Anyone that came up with a fix? Thanks
I am posting my solution in case it's helpful for others.
Although matt's answer is totally correct, it applies when all of you nav bar setup is done through UINavigationBarAppearance. This did not help in my case because I've already done this in AppDelegate:
// Make navigation bar transparent throughout whole app
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)
And as my app showcases a lot of nav bar styling and I needed a quick fix just to satisfy iOS 13 changes I just did this:
// Set nav bar to opaque
if #available(iOS 13.0, *) {
UINavigationBar.appearance().setBackgroundImage(nil, for: .default)
}
Just don't forget to bring it back to transparent if needed.
In iOS 13, the correct way to customize the look of a navigation bar is through the UIBarAppearance architecture (the navigation bar's standardAppearance and so forth). You can apply this directly to the navigation bar or use the UINavigationBar appearance proxy.
So my problem is that I cannot set the bar tint color on an iPhone 6 plus. I can set the bar tint color for all other devices but for the iPhone 6 plus the bar tint won't change. Here is the code for the view controller. Additionally, this VC is being pushed onto the stack by a navigation controller. Any help is majorly appreciated all.
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
navigationController?.navigationBar.barTintColor = .redColor()
navigationController?.navigationBar.translucent = false
navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.whiteColor()]
navigationController?.navigationBar.tintColor = UIColor.whiteColor()
}
This is the only thing that I am doing in the view controller and it doesn't work at all.
Ok so I solved the issue. For some reason, iPhone 6 plus calls
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
navigationController?.navigationBar.barTintColor = .primaryGrayColor()
navigationController?.navigationBar.translucent = false
navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.blackColor()]
}
every time a new view controller is pushed onto a navigation stack. This does not happen in the iPhone 5, iPhone 5s, iPhone 6 or the iPhone 7.