Related
My iOS app uses the storyboard for the UI and uses a custom tint for the background color of the navigation bar.
I have tested my app on the Xcode 13 beta 5 and the navigation bar is "white" and the text on the navigation bar is not visible.
In the apple developer forum at https://developer.apple.com/forums/thread/682420 it states that "In iOS 15, UIKit has extended the usage of the scrollEdgeAppearance, which by default produces a transparent background, to all navigation bars." To restore the old look, you must adopt the new UINavigationBar appearance APIs
I added the following code (from the link above) to the App Delegate "application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions":
if #available(iOS 13, *) {
let navigationController = UINavigationController(navigationBarClass: nil, toolbarClass: nil)
let navigationBar = navigationController.navigationBar
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = UIColor(red: 0.0/255.0, green: 125/255.0, blue: 0.0/255.0, alpha: 1.0)
navigationBar.standardAppearance = appearance;
navigationBar.scrollEdgeAppearance = navigationBar.standardAppearance
navigationBar.isTranslucent = false
}
This does not fix the problem. I still have the custom tint set in the storyboard editor for the navigation bar. Do I need to remove the custom tint or am I implementing the appearance API wrong?
To use your own colour scheme, use the following:
Swift
// White non-transucent navigatio bar, supports dark appearance
if #available(iOS 15, *) {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
}
Objective-c
if (#available(iOS 15.0, *)) {
UINavigationBarAppearance *navBarAppearance = [[UINavigationBarAppearance alloc] init];
navBarAppearance.backgroundColor = [UIColor redColor];
[navBarAppearance configureWithOpaqueBackground];
[UINavigationBar appearance].standardAppearance = navBarAppearance;
[UINavigationBar appearance].scrollEdgeAppearance = navBarAppearance;
}
To get the default translucent behaviour, the way the default was before iOS 15, just set the scrollEdgeAppearance:
Swift
if #available(iOS 15, *) {
UINavigationBar.appearance().scrollEdgeAppearance = UINavigationBarAppearance()
}
Objective-C
if (#available(iOS 15.0, *)) {
[UINavigationBar appearance].scrollEdgeAppearance = [[UINavigationBarAppearance alloc] init];
}
There is no need to change anything in the storyboard.
Here is the solution that finally worked when added to the App Delegate application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions:
//Fix Nav Bar tint issue in iOS 15.0 or later - is transparent w/o code below
if #available(iOS 15, *) {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.titleTextAttributes = [.foregroundColor: UIColor.white]
appearance.backgroundColor = UIColor(red: 0.0/255.0, green: 125/255.0, blue: 0.0/255.0, alpha: 1.0)
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
}
Note that it was necessary to set the title text attribute to "white" as the title text defaulted to black if this attribute was not specified.
Also note that this should only apply to iOS version 15.0 or later. It does not work for earlier versions as the storyboard navigation bar custom tint is the default behavior.
If anyone needs the Objective C version of G. Steve's answer
if (#available(iOS 15, *)){
UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];
[appearance configureWithOpaqueBackground];
appearance.titleTextAttributes = #{NSForegroundColorAttributeName : UIColor.whiteColor};
appearance.backgroundColor = [UIColor colorWithRed:0.0/255.0 green:125/255.0 blue:0.0/255.0 alpha:1.0];
[UINavigationBar appearance].standardAppearance = appearance;
[UINavigationBar appearance].scrollEdgeAppearance = appearance;
}
It get sorted for me in interface builder (xcode 13 - tested for iOS 13 and above) and did not need to check for iOS 15 availability (i.e. #available)
Choose standard and scroll edge appearances for the navigation bar.
Choose similar settings for both appearances
Good luck
In my case, when I update to xcode13 and iOS15。 I have found that navigationBar and tabBar turns transparent。 My viewController is embed in UINavigationController
After a series of tests, I found the Settings the backgroundColor of navigationController is best Way to fix this
navigationController?.view.backgroundColor = .yourColor
Once the color is set, everything is fine
This code can be put anywhere, not just in the App Delegate to fix the issue on iOS15:
if (#available(iOS 15, *)){
UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];
[appearance configureWithOpaqueBackground];
appearance.titleTextAttributes = #{NSForegroundColorAttributeName : UIColor.blackColor};
appearance.backgroundColor = [UIColor colorWithRed:0.0/255.0 green:125/255.0 blue:0.0/255.0 alpha:1.0];
self.navigationController.navigationBar.standardAppearance = appearance;
self.navigationController.navigationBar.scrollEdgeAppearance = appearance;
}
Xcode 13+
In iOS 15, UIKit has extended the usage of the scrollEdgeAppearance, which by default produces a transparent background, to all navigation bars. The background is controlled by when your scroll view scrolls content behind the navigation bar.
To restore the old look, you must adopt the new UINavigationBar appearance APIs, UINavigationBarAppearance. Remove your existing customizations and do something like this:
let appearance = UINavigationBarAppearance()
appearance.backgroundColor = <your tint color>
navigationBar.standardAppearance = appearance
navigationBar.scrollEdgeAppearance = appearance
You can also use the appearance proxy with the code above, but substituting navigationBar.appearance().scrollEdgeAppearance = appearance for the last line.
I've created this extension for supporting iOS 15 and iOS 12 for changing navigation bar background (tint) and title colors only in needed places, not over all application.
extension UINavigationBar {
func update(backroundColor: UIColor? = nil, titleColor: UIColor? = nil) {
if #available(iOS 15, *) {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
if let backroundColor = backroundColor {
appearance.backgroundColor = backroundColor
}
if let titleColor = titleColor {
appearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor: titleColor]
}
standardAppearance = appearance
scrollEdgeAppearance = appearance
} else {
barStyle = .blackTranslucent
if let backroundColor = backroundColor {
barTintColor = backroundColor
}
if let titleColor = titleColor {
titleTextAttributes = [NSAttributedString.Key.foregroundColor: titleColor]
}
}
}
}
and use it in needed places (in my case it's UI configuration of UIViewController) like this
func configureNavigationController() {
navigationController?.navigationBar.update(backroundColor: .blue, titleColor: .white)
}
I tried various ways but below code worked like Magic for restoring previous version.
if #available(iOS 15, *) {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = .white
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
}
My implementation of navigation bar configuration as opaque and as translucent for iOS 15 and older versions:
extension UINavigationBar {
static let defaultBackgroundColor = UIColor.red
static let defaultTintColor = UIColor.white
func setOpaque() {
if #available(iOS 15, *) {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = UINavigationBar.defaultBackgroundColor
appearance.titleTextAttributes = [.foregroundColor: UINavigationBar.defaultTintColor]
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
} else {
setBackgroundImage(UIImage(), for: UIBarPosition.any, barMetrics: UIBarMetrics.defaultPrompt)
shadowImage = UIImage()
barTintColor = UINavigationBar.defaultBackgroundColor
titleTextAttributes = [.foregroundColor: UINavigationBar.defaultTintColor]
}
isTranslucent = false
tintColor = UINavigationBar.defaultTintColor
}
func setTranslucent(tintColor: UIColor, titleColor: UIColor) {
if #available(iOS 15, *) {
let appearance = UINavigationBarAppearance()
appearance.configureWithTransparentBackground()
appearance.titleTextAttributes = [.foregroundColor: titleColor]
standardAppearance = appearance
scrollEdgeAppearance = appearance
} else {
titleTextAttributes = [.foregroundColor: titleColor]
setBackgroundImage(UIImage(), for: UIBarMetrics.default)
shadowImage = UIImage()
}
isTranslucent = true
self.tintColor = tintColor
}
}
Anybody looking for an objective-c solution, please try out the below code:
if (#available(iOS 15.0, *)) {
UINavigationBarAppearance *navBarAppearance = [[UINavigationBarAppearance alloc] init];
[navBarAppearance configureWithOpaqueBackground];
navBarAppearance.backgroundColor = YOUR_COLOR;
[navBarAppearance setTitleTextAttributes:
#{NSForegroundColorAttributeName:[UIColor whiteColor]}];
self.navigationController.navigationBar.standardAppearance = navBarAppearance;
self.navigationController.navigationBar.scrollEdgeAppearance = navBarAppearance;
}
In AppDelegate.swift
window?.backgroundColor = .white
worked in my case
Objective c code : implement this in your viewDidLoad function
if (#available(iOS 15, *)){
UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];
[appearance configureWithOpaqueBackground];
appearance.titleTextAttributes = #{NSForegroundColorAttributeName : UIColor.blackColor};
appearance.backgroundColor = [UIColor colorWithRed:0.0/255.0 green:125/255.0 blue:0.0/255.0 alpha:1.0];
self.navigationController.navigationBar.standardAppearance = appearance;
self.navigationController.navigationBar.scrollEdgeAppearance = appearance;
}
If we need to change the background color and selected and unselected item color, only this code worked in case of me
i have used this to change item appearance tabBarAppearance.stackedLayoutAppearance = tabBarItemAppearance
if #available(iOS 15.0, *) {
let tabBarAppearance = UITabBarAppearance()
let tabBarItemAppearance = UITabBarItemAppearance()
tabBarAppearance.backgroundColor = .white
tabBarItemAppearance.normal.titleTextAttributes = [NSAttributedString.Key.foregroundColor: Constants.Color.appDefaultBlue]
tabBarItemAppearance.selected.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.black]
tabBarAppearance.stackedLayoutAppearance = tabBarItemAppearance
tabBar.standardAppearance = tabBarAppearance
tabBar.scrollEdgeAppearance = tabBarAppearance
}
Make sure we use this code in TabBar class, to get the desired results, it might not work if we use it in the AppDelegate to set the appearance.
To do this with storyboard only, to build over #Atka's answer,
you can set customise title text attributes by opting for "Custom" title attributes
Here is a version if you want to set custom back button without title and transparent navigation bar
let backImg: UIImage = #imageLiteral(resourceName: "back")
if #available(iOS 15, *) {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.titleTextAttributes = [.foregroundColor: UIColor.black]
appearance.setBackIndicatorImage(backImg, transitionMaskImage: backImg)
appearance.backButtonAppearance.normal.titlePositionAdjustment =
UIOffset(horizontal: -1000.0, vertical: 0)
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
}
This code can be put anywhere, not just in the App Delegate to fix the issue on iOS15:
if #available(iOS 15, *) {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = <desired UIColor>
navigationBar.standardAppearance = appearance;
navigationBar.scrollEdgeAppearance = navigationBar.standardAppearance
}
Make like this:
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
I have edited the code shared by #Charlie Seligman as it did not work for me as I had a scroll view in one of my screen.
The below code works even if you have a scroll view and a navigation bar.
if #available(iOS 15, *) {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
appearance.backgroundColor = UIColor(red: 0.89, green: 0.06, blue: 0.00, alpha: 1.00)
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
}
In my application, I want to change tab bar title color and icon color when theme change on button click in iOS 13.
I set basic tabbar color in viewDidLoad.
override func viewDidLoad() {
super.viewDidLoad()
let appearance = self.tabBarController!.tabBar.standardAppearance.copy()
appearance.stackedLayoutAppearance.normal.iconColor = .red
appearance.stackedLayoutAppearance.normal.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.red]
appearance.stackedLayoutAppearance.selected.iconColor = .blue
appearance.stackedLayoutAppearance.selected.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.blue]
self.tabBarController!.tabBar.standardAppearance = appearance
}
When clicking on the button I want to change tab bar appearance but it is not working.
#IBAction func changeTabbarApperence(){
let appearance = self.tabBarController!.tabBar.standardAppearance.copy()
appearance.stackedLayoutAppearance.normal.iconColor = .green
appearance.stackedLayoutAppearance.normal.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.green]
appearance.stackedLayoutAppearance.selected.iconColor = .orange
appearance.stackedLayoutAppearance.selected.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.orange]
self.tabBarController!.tabBar.standardAppearance = appearance
}
Can anyone help me to implement this functionality? How can I change the tab bar appearance runtime?
I am working on UIViewController that contains a UIScrollView and it is constraint to the top of the view like that.
for setting the transparency for the navigation bar I use the following function:
func makeTransparentNavigationBar() {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithTransparentBackground()
navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.navigationBarText]
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.navigationBarText]
navBarAppearance.backgroundColor = UIColor.navigationBarBackground.withAlphaComponent(0)
navigationController?.navigationBar.standardAppearance = navBarAppearance
navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
}
However when I scroll up to a certain point I want to make it white opaque so i can add some text to the navigation title.
I have the following function for making an opaque navigation bar
func makeSolidtNavigationBar() {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.navigationBarText]
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.navigationBarText]
navBarAppearance.backgroundColor = UIColor.navigationBarBackground.withAlphaComponent(1)
navigationController?.navigationBar.standardAppearance = navBarAppearance
navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
}
To look like that:
The problem I am facing is that I can't call them one after the other: If I call makeSolidtNavigationBar() in my viewDidLoad when I call makeTransparentNavigationBar() it doesn't work and the other way around
any ideas?
Thank you in advance
Pre-conditions to reproduce the problem:
Xcode 11 beta + iOS 13 (latest version until Jun. 12 2019)
The navigation bar is in Large text mode
Specify the colour of navigation bar.
The status bar will remain in white in a real device, above the green navigation bar.
Solutions I tried:
Revert it back to iOS12 will solve it, but we will encounter iOS13 eventually...
disabling the large text mode will solve it...
hide the status bar will fix it, but it will cause status text overlapping with navigation bar item.
Any ideas? appreciate any help.
No hacks or funkiness required here. The key is defining the desired appearance and setting this value on BOTH the nav bar's standardAppearance AND its scrollEdgeAppearance. I have the following in the init for my base navigation controller subclass for my entire app:
if #available(iOS 13.0, *) {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
navBarAppearance.backgroundColor = <insert your color here>
navigationBar.standardAppearance = navBarAppearance
navigationBar.scrollEdgeAppearance = navBarAppearance
}
If the problem is that you'd like to give the navigation bar a color when the large title is showing, use the new UINavigationBarAppearance class.
let app = UINavigationBarAppearance()
app.backgroundColor = .blue
self.navigationController?.navigationBar.scrollEdgeAppearance = app
On iOS 13, navigation bars using large title have a transparent color per Apple human interface guidelines. See more infos here:
In iOS 13 and later, a large title navigation bar doesn’t include a background material or shadow by default. Also, a large title transitions to a standard title as people begin scrolling the content
Universal code
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.backgroundColor = // your color
navBarAppearance.shadowImage = nil // line
navBarAppearance.shadowColor = nil // line
UINavigationBar.appearance(whenContainedInInstancesOf: [UINavigationController.self]).standardAppearance = navBarAppearance
UINavigationBar.appearance(whenContainedInInstancesOf: [UINavigationController.self]).scrollEdgeAppearance = navBarAppearance
Objective C Solutions and iOS 13
UINavigationBarAppearance* navBarAppearance = [self.navigationController.navigationBar standardAppearance];
[navBarAppearance configureWithOpaqueBackground];
navBarAppearance.titleTextAttributes = #{NSForegroundColorAttributeName:TitleColor};
navBarAppearance.largeTitleTextAttributes = #{NSForegroundColorAttributeName: TitleColor};
navBarAppearance.backgroundColor = TopColor;
self.navigationController.navigationBar.standardAppearance = navBarAppearance;
self.navigationController.navigationBar.scrollEdgeAppearance = navBarAppearance;
my navigationBar extension, iOS 13 Swift 5
extension UIViewController {
func configureNavigationBar(largeTitleColor: UIColor, backgoundColor: UIColor, tintColor: UIColor, title: String, preferredLargeTitle: Bool) {
if #available(iOS 13.0, *) {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: largeTitleColor]
navBarAppearance.titleTextAttributes = [.foregroundColor: largeTitleColor]
navBarAppearance.backgroundColor = backgoundColor
navigationController?.navigationBar.standardAppearance = navBarAppearance
navigationController?.navigationBar.compactAppearance = navBarAppearance
navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
navigationController?.navigationBar.prefersLargeTitles = preferredLargeTitle
navigationController?.navigationBar.isTranslucent = false
navigationController?.navigationBar.tintColor = tintColor
navigationItem.title = title
} else {
// Fallback on earlier versions
navigationController?.navigationBar.barTintColor = backgoundColor
navigationController?.navigationBar.tintColor = tintColor
navigationController?.navigationBar.isTranslucent = false
navigationItem.title = title
}
}}
How to use:
configureNavigationBar(largeTitleColor: .yourColor, backgoundColor: .yourColor, tintColor: .yourColor, title: "YourTitle", preferredLargeTitle: true)
Set ViewController-based status bar...... to NO in info.plist if you want light Content
If you don't want largeTitles set it to false
Tested on iOS 13, hope this help :)
If you want to remove the underline below the nav bar
if #available(iOS 13.0, *) {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
navBarAppearance.backgroundColor = <yourColor>
navBarAppearance.backgroundImage = UIImage()
navBarAppearance.shadowImage = UIImage()
navBarAppearance.shadowColor = .clear
self.navigationController?.navigationBar.standardAppearance = navBarAppearance
self.navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
}
For iOS 13 I was having a problem with the bar's shadow line showing up. Setting the Bars shadow image to nil solved that issue.
Before
func configureNavigation() {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.myColor,
.font: UIFont(name: "MyFont", size: 42)!]
navBarAppearance.backgroundColor = .white
navigationController?.navigationBar.isTranslucent = false
navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
}
After
func configureNavigation() {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.myColor,
.font: UIFont(name: "MyFont", size: 42)!]
navBarAppearance.backgroundColor = .white
navBarAppearance.shadowColor = nil
navigationController?.navigationBar.isTranslucent = false
navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
}
Fully workable code:
let navigationBarAppearace = UINavigationBar.appearance()
navigationBarAppearace.tintColor = .tintColor
navigationBarAppearace.barTintColor = .barTintColor
navigationBarAppearace.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.tintColor]
if #available(iOS 13.0, *) {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.tintColor]
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.tintColor]
navBarAppearance.backgroundColor = <insert your color here>
navigationBarAppearace.standardAppearance = navBarAppearance // have a look here ;)
navigationBar.scrollEdgeAppearance = navBarAppearance
}
Good luck all, Peace!
Thanks to Mike and Hans's answer. My case is half transparent status bar and nav bar with alpha 0.5. iOS13 seems complicated. Below is my test result, will work if you want transparent for both.
if #available(iOS 13.0, *) {
let navBarAppearance = UINavigationBarAppearance()
// This only set top status bar as transparent, not the nav bar.
navBarAppearance .configureWithTransparentBackground()
// This set the color for both status bar and nav bar(alpha 1).
navBarAppearance.backgroundColor = UIColor.red.withAlphaComponent(0.5)
navigationController?.navigationBar.standardAppearance = navBarAppearance
navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
// Nav bar need sets to translucent for both nav bar and status bar to be translucent.
navigationController?.navigationBar.isTranslucent = true
// // Need to reset nav bar's color to make it clear to display navBarAppearance's color
navigationController?.navigationBar.backgroundColor = UIColor.clear
}
I had a similar problem when updating one of my apps to be more iOS 13 compatible. As Hans mentioned above, the large titles are transparent by default. If you are a heavy Storyboard user as I am, there's another setting in the side bar that's easy to turn on.
If you click on your nav bar in the story board, it usually defaults to selecting the Navigation Item, and you won't get any customization options. Select the Navigation Bar option above it, and then you are able to choose a custom background color of whatever you want over in the Inspector on the right.
I've discovered that with storyboards you have to fake the nav bar (only really works with opaque nav bars, assuming your green is opaque). The best way I found was to create a placeholder view (purple) that fits the safe area insets, and then add a fake view behind the nav bar (cyan/blue) that is the height remaining. Works for my project, but yeah it's a bit of a hack.
Edit: This is mainly for LaunchScreen.storyboard where you can't use a custom view controller class.
Swift 5
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
let userInterfaceStyle = traitCollection.userInterfaceStyle
modeDetect(userInterfaceStyle: userInterfaceStyle)
}
override func viewDidAppear(_ animated: Bool) {
navigationController?.navigationBar.barStyle = .black
navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.white]
}
func modeDetect(userInterfaceStyle: UIUserInterfaceStyle) {
switch userInterfaceStyle {
case .light:
navigationController?.navigationBar.barTintColor = .systemPink
case .dark:
navigationController?.navigationBar.barTintColor = .systemBackground
default:
break
}
}
Call this function with a proper argument.
This code is working properly.
open func showNavigationBar(large: Bool,
animated: Bool,
isTransparabar: Bool,
titleColor: UIColor,
barBackGroundColor: UIColor,
fontSize: CGFloat) {
navigationController?.navigationBar.barTintColor = barBackGroundColor
navigationController?.navigationBar.backgroundColor = barBackGroundColor
navigationController?.navigationBar.isTranslucent = true
self.navigationController?.setNavigationBarHidden(false, animated: animated)
if large {
self.navigationController?.navigationBar.prefersLargeTitles = true
if #available(iOS 13.0, *) {
let appearance = UINavigationBarAppearance()
appearance.backgroundColor = barBackGroundColor
appearance.titleTextAttributes = [.foregroundColor: titleColor]
appearance.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: titleColor]
navigationController?.navigationBar.standardAppearance = appearance
navigationController?.navigationBar.compactAppearance = appearance
navigationController?.navigationBar.scrollEdgeAppearance = appearance
} else {
self.navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: titleColor]
}
} else {
self.navigationController?.navigationBar.prefersLargeTitles = false
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: titleColor!]
}
}
The following Objective-C code made iOS 13 navigation bar behave like the previous version for me:
if (#available(iOS 13.0, *)) {
// Setup iOS 13 navigation bar
sharedSelector.navigationBar.scrollEdgeAppearance = sharedSelector.navigationBar.standardAppearance;
} else {
// Fallback on earlier versions
}
I just turn on translucent in storyboard
#mohmmad alabid's answer would need to be applied to each view controller seperately, if you want a generic objective-c solution put this in your app delegate inside the didFinishLaunchingWithOptions function.
if (#available(iOS 13.0, *)) {
UINavigationBarAppearance* navBarAppearance = [[UINavigationBarAppearance alloc] init];
[navBarAppearance configureWithOpaqueBackground];
navBarAppearance.titleTextAttributes = #{NSForegroundColorAttributeName:NAVBAR_TEXT_COLOR};
navBarAppearance.largeTitleTextAttributes = #{NSForegroundColorAttributeName: NAVBAR_TEXT_COLOR};
navBarAppearance.backgroundColor = NAVBAR_COLOR;
[[UINavigationBar appearance] setStandardAppearance: navBarAppearance];
[[UINavigationBar appearance] setScrollEdgeAppearance: navBarAppearance];
}
Mike's solution is great.
I offer an alternative approach to change the UINavigationBar color which applies to any iOS version.
We are basically going to exploit the fact that we can set an Image as the UINavigationBar's background.
FIRST
Add an extension to generate a UIImage from any UColor. Note that you can also also write an extension later to generate UIColor from hexadecimals or other formats if you want.
extension UIColor {
func image(_ size: CGSize = CGSize(width: 1, height: 1)) -> UIImage {
return UIGraphicsImageRenderer(size: size).image { rendererContext in
self.setFill()
rendererContext.fill(CGRect(origin: .zero, size: size))
}
}
}
Thanks #neoneye for this great UIColor extension :)
SECOND
Now we get down to business:
private func setupNavigationBarAppearance(navBar: UINavigationBar) {
navBar.isTranslucent = false
let navBarColorImage = UIColor.blue.image()
navBar.setBackgroundImage(navBarColorImage, for: .default)
navBar.tintColor = UIColor.white
}
Because we've setup the opaque colored image as the background, we do not need to check for iOS 13.
I hope this help some folks to customize their NavBars.
Cheers!
On ios13, with iphone x, the large title navigation does not cover the status bar however when scrolling and transitioning into the traditional nav bar, it works perfectly. This doesn't affect devices without the notch.
Large titles
Traditional navigation bar
It's all embedded within a navigation controller so i'm lost as to why this is happening. Cheers
The official way to customize the UINavigationBar, pre iOS 13, is this:
// text/button color
UINavigationBar.appearance().tintColor = .white
// background color
UINavigationBar.appearance().barTintColor = .purple
// required to disable blur effect & allow barTintColor to work
UINavigationBar.appearance().isTranslucent = false
iOS 13 has changed how navigation bars work, so you'll need to do things slightly differently to support both old & new:
if #available(iOS 13.0, *) {
let appearance = UINavigationBarAppearance()
appearance.backgroundColor = .purple
appearance.titleTextAttributes = [.foregroundColor: UIColor.white]
appearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
UINavigationBar.appearance().tintColor = .white
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().compactAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
} else {
UINavigationBar.appearance().tintColor = .white
UINavigationBar.appearance().barTintColor = .purple
UINavigationBar.appearance().isTranslucent = false
}
Use my extension iOS 13 Swift 5 tested
extension UIViewController {
func configureNavigationBar(largeTitleColor: UIColor, backgoundColor: UIColor, tintColor: UIColor, title: String, preferredLargeTitle: Bool) {
if #available(iOS 13.0, *) {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: largeTitleColor]
navBarAppearance.titleTextAttributes = [.foregroundColor: largeTitleColor]
navBarAppearance.backgroundColor = backgoundColor
navigationController?.navigationBar.standardAppearance = navBarAppearance
navigationController?.navigationBar.compactAppearance = navBarAppearance
navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
navigationController?.navigationBar.prefersLargeTitles = preferredLargeTitle
navigationController?.navigationBar.isTranslucent = false
navigationController?.navigationBar.tintColor = tintColor
navigationItem.title = title
} else {
// Fallback on earlier versions
navigationController?.navigationBar.barTintColor = backgoundColor
navigationController?.navigationBar.tintColor = tintColor
navigationController?.navigationBar.isTranslucent = false
navigationItem.title = title
}
}}
How to use:
configureNavigationBar(largeTitleColor: .yourColor, backgoundColor: .yourColor, tintColor: .yourColor, title: "yuorTitle", preferredLargeTitle: true)
Set ViewController-based status bar...... to NO in info.plist if you want light Content
If you don't want largeTitles set it to false
for tranlsucent change navBarAppearance.configureWithOpaqueBackground() in:
navBarAppearance.configureWithDefaultBackground()
navigationController?.navigationBar.isTranslucent = true
in the call set background color to .clear
UPDATE:
If you want to start with navigation controller and large Titles at first controller, don't forget to set launch controller in Scene Delegate like this:
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
window?.makeKeyAndVisible()
let vC = UINavigationController(rootViewController: YourFirstViewController())
window?.rootViewController = vC
hope this help :)
For full application navigation bar support please add this extension inside your code.
import UIKit
extension UIViewController {
open func showNavigationBar(_ large: Bool,
_ animated: Bool,
titleColor: UIColor,
barTintColor: UIColor,
fontSize: CGFloat) {
navigationController?.navigationBar.barTintColor = barTintColor
navigationController?.navigationBar.backgroundColor = barTintColor
navigationController?.navigationBar.isTranslucent = true
self.navigationController?.setNavigationBarHidden(false, animated: animated)
if large {
self.navigationController?.navigationBar.prefersLargeTitles = true
if #available(iOS 13.0, *) {
let appearance = UINavigationBarAppearance()
appearance.backgroundColor = barTintColor
appearance.titleTextAttributes = [.foregroundColor: titleColor]
appearance.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: titleColor,
NSAttributedString.Key.font: UIFont(resource: R.font.robotoMedium, size: fontSize)!]
navigationController?.navigationBar.standardAppearance = appearance
navigationController?.navigationBar.compactAppearance = appearance
navigationController?.navigationBar.scrollEdgeAppearance = appearance
} else {
self.navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: titleColor,
NSAttributedString.Key.font: UIFont(resource: R.font.robotoMedium, size: fontSize)!]
}
} else {
self.navigationController?.navigationBar.prefersLargeTitles = false
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: titleColor,
NSAttributedString.Key.font: UIFont(resource: R.font.robotoMedium, size: 20.0)!]
}
}
}
And Then call this method simply
self.showNavigationBar(true, true, titleColor: UIColor.blue, barTintColor: UIColor.red, fontSize: 32.0)