How to use UINavigationBarAppearance in iOS 13 - ios

How do you use this new object to customize the navigation bar in iOS 13? I tried the following code in Objective-C but it's not working correctly. It only shows my title text attributes while a view controller is being pushed or popped on to the navigation stack.
UINavigationBarAppearance *appearance = [UINavigationBarAppearance new];
appearance.titleTextAttributes = #{NSFontAttributeName: font};
Here is the documentation for this object.
https://developer.apple.com/documentation/uikit/uinavigationbarappearance?language=objc

It isn't enough to just create an instance of UINavigationBarAppearance. You have to actually set it on a UINavigationBar instance (or its appearance proxy).
// Setup the nav bar appearance
UINavigationBarAppearance *appearance = [UINavigationBarAppearance new];
appearance.titleTextAttributes = #{NSFontAttributeName: font};
// Apply it to a specific nav bar
someNavBarInstance.standardAppearance = appearance;
// There are also the compactAppearance and scrollEdgeAppearance properties that can be set as needed.
If you want this same customization on all nav bars in the app, apply it to the UINavigationBar.appearance proxy.
UINavigationBar.appearance.standardAppearance = appearance;

For me, even though I correctly set the appearance to the current UINavigationBar, it was still not working.
I found out that you need to call navigationBar?.setNeedsLayout(), if you set an updated appearance on a UINavigationBar that is already being displayed.

in iOS13 you need to set the title color on the UINavigationBarAppearance object like here (Objective C version):
UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];
appearance.titleTextAttributes = #{NSForegroundColorAttributeName: [UIColor whiteColor]};
self.navigationController.navigationBar.standardAppearance = appearance;
self.navigationController.navigationBar.scrollEdgeAppearance = appearance;

Related

Why the view.safeAreaInset is same for Opaque and Transparent UINavigationBarAppearance?

When we use the old way of making the navigation bar translucent or opaque using isTranslucent property on the navigation bar, the view's safeAreaInset returns some value other than 0 for the translucent navigation bar and viceVersa.
But this behaviour is not seen when using the below code as pe new iOS 13 SDK
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = UIColor.systemRed
appearance.titleTextAttributes = [.foregroundColor: UIColor.lightText] // With a red background, make the title more readable.
navigationItem.standardAppearance = appearance
navigationItem.scrollEdgeAppearance = appearance
navigationItem.compactAppearance = appearanc
For this code i am still seeing safeAreaInset.top > 0.
Please help me to understand this behaviour. And how to get inset.top as 0 with new UINavigationBarAppearance api.
Answering my own question:
Using isTranslusent with Appearance API helped me to achieve the old behavior.
As appearance.configureWithOpaqueBackground() only make the bar appearance opaque.

Customizing UINavigationBar not working because of weird UINavigationBar view hierarchy

My app has many ViewControllers that are pushed on navigation stack.
I have configured UINavigationBar appearance globally in AppDelegate as below.
let appearance = UINavigationBar.appearance()
appearance.barTintColor = myColor
appearance.tintColor = .white
appearance.isTranslucent = false
let textAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white,
NSAttributedString.Key.font: myFont, size: mySize)]
appearance.titleTextAttributes = textAttributes as [NSAttributedString.Key : Any]
All ViewControllers work as expected except only one ViewController.
Below is one of the VCs that works as expected. It shows color and font that I want.
And below is the ViewController that shows different look unlike others.
I can't understand the reason why only one navigationBar on this VC shows different appearance.
So I've done debugging view hierarchy.
Below is the view hierarchy of VCs that works as expected.
And below is the view hierarchy of VC that shows weird look.
As seen on the picture, the problematic NavigationBar has two more layers, UIVisualEffectView and UIVisualEffectBackdropView.
I am an experienced iOS developer and have no idea why this happens.
I carefully checked all the setting related to NavigationBar on the IB but found no difference from others.
I even removed the ViewController, embedding NavigationController completely and rebuilt them from scratch without luck.
Please somebody explain me why only this NavigationBar has different structure.
I'm working on iOS 13.3 & Xcode 11.3.1
Working here on iOS15, I tried a lot of things to customize the nav bar appearance to achieve a simple opaque color, nothing worked except this:
In viewDidLoad
if (#available(iOS 13.0, *)) {
UINavigationBarAppearance *appearance = [UINavigationBarAppearance new];
appearance.backgroundColor = [UIColor orangeColor];
self.navigationController.navigationBar.standardAppearance = appearance;
self.navigationController.navigationBar.scrollEdgeAppearance = appearance;
}
Swift version:
let appearance = UINavigationBarAppearance()
appearance.backgroundColor = .orange
navigationBar.standardAppearance = appearance;
navigationBar.scrollEdgeAppearance = navigationBar.standardAppearance
Finally if you only want to apply this on the current controller, and restore the default nav bar just do the same but with a fresh UINavigationBarAppearance() on viewWillDisappear.

How to make UINavigationBar background transparent?

First of all,
I've seen all the answers at How to make UINavigationBar Transparent in IOS 8? Transparent UINavigationBar and Make UINavigationBar transparent.
They just don't seem to work for me.
My regular view controller (before trying to make the navigation bar transparent) doesn't have any issues:
I'm using (tried both in viewDidLoad and viewWillAppear:):
[self.navigationController.navigationBar setBackgroundImage:[UIImage new]
forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.shadowImage = [UIImage new];
self.navigationController.navigationBar.translucent = YES;
self.navigationController.view.backgroundColor = [UIColor clearColor];
I'm getting this:
Gray status bar background, completely white navigation bar which doesn't blend with the status bar, and then the view starts. All the 'solutions' at the other questions' answers' yield the same result for me.
I've also tried setting self.edgesForExtendedLayout = UIRectEdgeNone; or self.edgesForExtendedLayout = UIRectEdgeAll; but that also didn't have any impact.
How can I make my navigation bar transparent without messing up everything?
UPDATE: Following Warif Akhand Rishi's answer, I've changed self.navigationController.view.backgroundColor = [UIColor clearColor]; to self.navigationController.navigationBar.backgroundColor = [UIColor clearColor];, now I'm getting a gray, unified status/navbar, but still not transparent:
UPDATE 2: I've hooked up the view debugger, and that gray background seems to come from deep down from the roots of view hierarchy, and my view's content is not extending up. I've tried self.edgesForExtendedLayout = UIRectEdgeAll; again with the latest code but still no avail:
swift 4 transparent nav bar:
(be sure view extends behind nav bar to show through, otherwise will just be black)
navigationController?.navigationBar.isTranslucent = true
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
navigationController?.navigationBar.shadowImage = UIImage() //remove pesky 1 pixel line
or just match navbar color to color of your current vc, but keep it opaque. with translucent set to false child views will line up with navbar instead of going under it.
navigationController?.navigationBar.isTranslucent = false
navigationController?.navigationBar.barTintColor = UIColor.yourColor
navigationController?.navigationBar.shadowImage = UIImage() //remove pesky 1 pixel line
Change your
self.navigationController.view.backgroundColor = [UIColor clearColor];
to this
self.navigationController.navigationBar.backgroundColor = [UIColor clearColor];
Okay, after struggling, I've solved the problem on my own. There was more than one problem. It wasn't about the extended edges, it was about the line self.navigationController.view.backgroundColor = [UIColor clearColor]; (which had to be self.navigationController.navigationBar.backgroundColor = [UIColor clearColor]; as Warif Akhand Rishi suggested) and also my table view's clip subviews property. I've changed that line and also turned off clipping of my table view and now it works as expected.
For iOS 13 and the UINavigationBarAppearance API:
let navAppearance = UINavigationBarAppearance()
navAppearance.configureWithTransparentBackground()
self.navigationItem.standardAppearance = navAppearance
Eliminate 5+ lines of shadow/background/color code!
I'm a little late to the party, but I recently needed to do the same thing and I found the following actually works best (because it removes all shadows and bleed-throughs you may have from something lower in the stack):
guard let navBar = navigationController?.navigationBar else { return }
navBar.barStyle = .black
navBar.setBackgroundImage(UIImage(), for: .default)
navBar.shadowImage = UIImage()
navBar.isTranslucent = true
navBar.isHidden = false
1.Your NavigationBar is white,not black.So you must have a view (a white view) under NavigationBar,which is the superview of your greyView.The transparent setting works,but you cann't see it ,because the fontcolor is white too.
2.So you have to update your greyView's constraints,so it can extends under navigationbar .And then you can see your white title.
3.Maybe you have to Change your statusBar's UIStatusBarStyle to default or lightcontent,I noticed the font color of statusBar is white too.
The below code works for me
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.isTranslucent = true
self.navigationController?.view.backgroundColor = .clear
self.navigationController?.navigationBar.backgroundColor = .clear

Customising same UINavigationBar within app multiple times

I am customising UINavigationBar with different color and custom font by using titleTextAttributes. However, when I moved to another view, I would like to use different color from previous with same custom font.
I have used,
[[UINavigationBar appearance] setTitleTextAttributes:mySettings]
in AppDelegate.m. When call same method with newSettings in viewDidLoad of another viewController, it doesn't get reflected.
I am able to change bar color or bar tint color in viewDidLoad of another viewController. However, my title foreground color is not changing. Am I missing anything?
Last solution which I have to have custom titleView. But wanted to avoid it. Any inputs?
[[UINavigationBar appearance] setTitleTextAttributes:mySettings] is a global configuration, so that's the reason why changing it in the other view controllers doesn't work. I believe you won't getting around customizing the titleView property of navigation item,... :/
You can do this by creating a UILabel that has the settings that you want and then assign it to the property:
NSAttributedString *title = [[NSAttributedString alloc] string:"the title" attributes:mySettings];
UILabel *newTitleView = [[UILabel alloc] init];
newTitleView.attributedText = title;
self.navigationItem.titleView = newTitleView;

Why does my app look like this in the multitasking drawer?

In my AppDelegate I've customized the colors of the UINavigationBar, but when I double tap the home button to open the multitasking drawer, my app preview looks like this:
When in reality its supposed to look like this:
(Just ignore the different content in app.)
This is the code I use for changeing colors and fonts:
// set navigation bar colors
UINavigationBar *navigationBar = [UINavigationBar appearance];
navigationBar.barTintColor = redColor;
navigationBar.tintColor = [UIColor whiteColor];
navigationBar.titleTextAttributes = #{
NSForegroundColorAttributeName: [UIColor whiteColor],
NSFontAttributeName: [UIFont fontWithName:#"SOLIDARITET" size:26.0]
};
Found the solution. I selected my Storyboard file, and set the background color in the Attributes Inspector from currentColor to whiteColor.

Resources