iOS13 Navigation bar large titles not covering status bar
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
}
In iOS13 the status bar background colour is different from the navigation bar in large text mode
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
}
Swift UINavigationBar background image does not cover status bar when clipToBounds is true
We've solved this as followed:
We set the background image on ViewController. This is the same as we use in navigation bar.
let imageView = UIImageView(image: .assetImage(.background))
imageView.contentMode = .topLeft
collectionView.backgroundView = imageView
Style the navigation bar.
// General Styling
UINavigationBar.appearance().tintColor = .assetColor(.navigationBarTintColor)
// Bar Styling
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.shadowColor = .clear
navBarAppearance.backgroundColor = UIColor(patternImage: .assetImage(.background)!)
UINavigationBar.appearance().standardAppearance = navBarAppearance
UINavigationBar.appearance().scrollEdgeAppearance = navBarAppearance
In addition we change the translucent of the navigation bar for non-root views:
if isRootview {
self.navigationController?.navigationBar.isTranslucent = true
} else {
self.navigationController?.navigationBar.isTranslucent = false
}
Navigation Bar Large Title - Animation Issue
for second issue:
in SceneDelegate: var window: UIWindow?
in the function scene put this line:
window?.backgroundColor = .yourColor
like this:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
guard let _ = (scene as? UIWindowScene) else { return }
window?.backgroundColor = .white
}
set the color you want and that's it :)
Can large titles be maintain when the user scrolls within a navigation controller
Ok, I've solved my issue with a simple workaround that works great. Instead of adding my UIScrollView
to the UIViewController.view
and constraining it to the view.topAnchor
, I've added a UIView
[named staticView] to my UIViewController. Constraining that staticView to the view.topAnchor
and then constraining UIScrollView
to my static view prevents the largeTitles from being reduced, while still allowing the user to scroll.
When a UIScrollView
is constrained to the topAnchor the OS reduces the nav bars large titles to their default size as the user scrolls. Having the scroll view pinned to the static view interrupts this behaviour and the large titles remain.
How do you round bottom corners of UINavigation bar with a search bar using large titles
so I found that this works, however, now my search bar text is black on purple vs white? - And I had to set the background color of the view to my purple color and then place a white background view on top of the view. Thoughts?
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.prefersLargeTitles = true
self.navigationController?.navigationBar.layer.cornerRadius = 30
self.navigationController?.navigationBar.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
self.navigationController?.navigationBar.clipsToBounds = true
let app = UINavigationBarAppearance()
app.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
app.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
app.backgroundColor = UIColor(red: 0.30, green: 0.07, blue: 0.63, alpha: 1.00)
self.navigationController?.navigationBar.scrollEdgeAppearance = app
self.navigationController?.navigationBar.isOpaque = true
search.searchBar.delegate = self
UISearchBar.appearance().tintColor = .white
search.searchBar.searchTextField.textColor = .white
search.searchBar.sizeToFit()
search.obscuresBackgroundDuringPresentation = false
search.hidesNavigationBarDuringPresentation = false
self.definesPresentationContext = true
search.searchBar.placeholder = "Search here"
self.navigationItem.searchController = search
}
Set border and color of navigationbar when largetitles = true
I got this to work now. If anyone has the same problem it can be done with this code:
if #available(iOS 13.0, *) {
let appearance = UINavigationBarAppearance()
appearance.backgroundColor = UIColor(displayP3Red: 248/255, green: 248/255, blue: 248/255, alpha: 1)
appearance.titleTextAttributes = [.foregroundColor: UIColor.black]
appearance.largeTitleTextAttributes = [.foregroundColor: UIColor.black]
UINavigationBar.appearance().tintColor = .systemBlue
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().compactAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
} else {
UINavigationBar.appearance().tintColor = .systemBlue
UINavigationBar.appearance().barTintColor = UIColor(displayP3Red: 248/255, green: 248/255, blue: 248/255, alpha: 1)
UINavigationBar.appearance().isTranslucent = false
}
You need to put this in
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { }
otherwise, the first view controller does not have these changes, because the first view is already loaded.
Thanks to @Sebastion who post something similar in this post: iOS13 Navigation bar large titles not covering status bar
Related Topics
Is Swiftui Backwards-Compatible With iOS 12.X and Older
How to Use the Appropriate Color Class For the Current Platform
Can Associated Values and Raw Values Coexist in Swift Enumeration
Swift: Determine What Object Called a Function
Simpliest Solution to Check If File Exists on a Webserver. (Swift)
How to Animate a Model's Rotation in Realitykit
How to Convert a Uiimage to a Cvpixelbuffer
Pass Variables from One Viewcontroller to Another in Swift
Using Variables Outside of Completion Block
How to Detect a Swiftui Touchdown Event with No Movement or Duration