I have a view controller in my navigation stack that needs to have a transparent navigation bar, while still showing the back button.
I'm able to achieve that with one line of code inside viewWillAppear:
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
However, when I try to go back to the previous view, I'm setting the background image back to nil or .none but I'm losing the translucent effect that was previously on there when I do that.
I've tried setting all the following options in viewWillDisappear and none seem to bring the translucency back. It just appears white no matter what I do. The shadow on the bottom is also gone too:
self.navigationController?.navigationBar.isTranslucent = true
self.navigationController?.navigationBar.barStyle = .default
self.navigationController?.navigationBar.backgroundColor = .none
self.navigationController?.navigationBar.setBackgroundImage(.none, for: .default)
Initial Navigation Bar:
Transparent Navigation Bar:
After Transitioning Back:
In viewWillAppear make the navigation bar transparent
override func viewWillAppear(_ animated: Bool) { self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.isTranslucent = true
}
And backg to translucent in viewWillDisappear
override func viewWillDisappear(_ animated: Bool) {
self.navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
self.navigationController?.navigationBar.shadowImage = nil
self.navigationController?.navigationBar.isTranslucent = false
}
After spending time poking around in the UINavigationBar internals, I did discover a simple method that seems to work, and does not require any configuration of the standard UINavigationBar attributes we've previously fiddled with to achieve transparency. The following is tested working on iOS 12.2.x:
class TallNavigationBar: UINavigationBar {
private lazy var maskingView: UIView = {
let view = UIView(frame: bounds)
view.backgroundColor = .clear
return view
}()
var isTransparent = false {
didSet {
guard isTransparent != oldValue, let bkgView = subviews.first else { return }
bkgView.mask = isTransparent ? maskingView : nil
}
}
}
Obviously, whenever fiddling (even slightly) with undocumented internals: use at your own risk!
This worked for my app which needs to revert to an opaque navigation bar after popping from a transparent navigation bar.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
navigationController?.navigationBar.shadowImage = nil
navigationController?.navigationBar.isTranslucent = true
navigationController?.navigationBar.backgroundColor = nil
}
Related
I need to show large navigation title while search with searchBar, but when I'm clicking on Searchbar or starting to type my NavigationTitle is replaced with SearchBar. I checked methods for navigationItem and didn't find any suitable.
Does anybody know how can we always show title, even while searching?
Here is my code
class FavouriteVC: UIViewController {
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.title = "Favourite"
navigationItem.searchController = searchController
navigationItem.largeTitleDisplayMode = .always
}
}
And here are shots
screen with NavTitle
screen without NavTitle
Seems like UISearchController has a hidesNavigationBarDuringPresentation that prevents the navigation bar from hiding when set to false
Include:
searchController.hidesNavigationBarDuringPresentation = false
in your viewDidLoad and if I've understood your issue right, this should do what you need.
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
When applying transparent image in the navigation tab bar. It's turning white instead of being transparent..
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.tintColor = UIColor.white
Ensure that something is under the navigation bar so that it does not just become transparent showing the white background. You will need to drag uiviews under it and then add layout constraints. Otherwise, make sure you check that you have not changed the color of the navigation bar elsewhere.
Use this extension to make navigation bar transperant.
extension UINavigationController {
func transparant() {
self.navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
self.navigationBar.shadowImage = UIImage()
self.navigationBar.isTranslucent = true
self.view.backgroundColor = UIColor.clear
}
}
if you are using Navigation Controller try this:
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationController?.navigationBar.shadowImage = UIImage()
title = "Some Title"
if you are using UINavigationBar try this:
#IBOutlet var navBarOutlet: UINavigationBar!
override func viewDidLoad() {
super.viewDidLoad()
// navigatin bar transparent
navBarOutlet.setBackgroundImage(UIImage(),for:.default)
navBarOutlet.shadowImage=UIImage()
navBarOutlet.topItem?.title = "Some Title"
}
My bug:
If navigate from a view controller with large titles enabled to a view controller with large titles disabled i see same bug. Height navigation bar changes not smoothy.
I want animation change height navBar during segue on another viewController like this
Common propertyes for navBar set up in BaseNavigationController
class BaseNavigationController: UINavigationController {
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
override func viewDidLoad() {
super.viewDidLoad()
setNavBarTitlesPropertyes()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
private func setNavBarTitlesPropertyes() {
navigationBar.tintColor = .white
navigationBar.titleTextAttributes = [
.foregroundColor: UIColor.white
]
if #available(iOS 11.0, *) {
navigationBar.prefersLargeTitles = true
navigationBar.largeTitleTextAttributes = [
.foregroundColor: UIColor.white
]
}
}
And my setting navbar in the storyboard:
I found solution for this trouble. UINavigationBar
property translucent should be true, and also bottom and top constraint for tableView in UIViewController should be equal Superview.Top and Superview.Bottom accordingly.
Team, I have a navigation bar set up to be transparent but I am still getting a "ghost" image during the transition. Am I missing a property that needs to be set to clear?
code to make view controller transparent:
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.isTranslucent = true
Here is before the transition:
BeforeImage
During the transition:
DuringImage
After the transition:
AfterImage
For my app, I did this in viewWillAppear:
override func viewWillAppear(_ animated: Bool) {
self.navigationController!.navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.isTranslucent = true
self.navigationController!.navigationBar.backgroundColor = UIColor.clear
}
Mine doesn't have a little ghost flash in there, so maybe this will help. Looks like you just need to add the backgroundColor. Try it out and let me know.