How to hide UINavigationBar 1px bottom line
Solution 1
For iOS 13:
Use the .shadowColor
property
If this property is nil or contains the clear color, the bar displays no shadow
For instance:
let navigationBar = navigationController?.navigationBar
let navigationBarAppearance = UINavigationBarAppearance()
navigationBarAppearance.shadowColor = .clear
navigationBar?.scrollEdgeAppearance = navigationBarAppearance
For iOS 12 and below:
To do this, you should set a custom shadow image. But for the shadow image to be shown you also need to set a custom background image, quote from Apple's documentation:
For a custom shadow image to be shown, a custom background image must also be set with the setBackgroundImage(_:for:) method. If the default background image is used, then the default shadow image will be used regardless of the value of this property.
So:
let navigationBar = navigationController!.navigationBar
navigationBar.setBackgroundImage(#imageLiteral(resourceName: "BarBackground"),
for: .default)
navigationBar.shadowImage = UIImage()
Above is the only "official" way to hide it. Unfortunately, it removes bar's translucency.
I don't want background image, just color##
You have those options:
-
Solid color, no translucency:
navigationBar.barTintColor = UIColor.redColor() navigationBar.isTranslucent = false navigationBar.setBackgroundImage(UIImage(), for: .default) navigationBar.shadowImage = UIImage()
-
Create small background image filled with color and use it.
-
Use 'hacky' method described below. It will also keep bar translucent.
How to keep bar translucent?##
To keep translucency you need another approach, it looks like a hack but works well. The shadow we're trying to remove is a hairline UIImageView
somewhere under UINavigationBar
. We can find it and hide/show it when needed.
Instructions below assume you need hairline hidden only in one controller of your UINavigationController
hierarchy.
-
Declare instance variable:
private var shadowImageView: UIImageView?
-
Add method which finds this shadow (hairline)
UIImageView:
private func findShadowImage(under view: UIView) -> UIImageView? { if view is UIImageView && view.bounds.size.height <= 1 { return (view as! UIImageView) } for subview in view.subviews { if let imageView = findShadowImage(under: subview) { return imageView } } return nil }
-
Add/edit
viewWillAppear/viewWillDisappear
methods:override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) if shadowImageView == nil { shadowImageView = findShadowImage(under: navigationController!.navigationBar) } shadowImageView?.isHidden = true } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) shadowImageView?.isHidden = false }
The same method should also work for UISearchBar
hairline,
and (almost) anything else you need to hide :)
Many thanks to @Leo Natan for the original idea!
Solution 2
Here is the hack. Since it works on key paths might break in the future. But for now it works as expected.
Swift:
self.navigationController?.navigationBar.setValue(true, forKey: "hidesShadow")
Objective C:
[self.navigationController.navigationBar setValue:@(YES) forKeyPath:@"hidesShadow"];
Solution 3
If you just want to use a solid navigation bar color and have set this up in your storyboard, use this code in your AppDelegate
class to remove the 1 pixel border via the appearance proxy:
[[UINavigationBar appearance] setBackgroundImage:[[UIImage alloc] init]
forBarPosition:UIBarPositionAny
barMetrics:UIBarMetricsDefault];
[[UINavigationBar appearance] setShadowImage:[[UIImage alloc] init]];
Solution 4
Try this:
[[UINavigationBar appearance] setBackgroundImage: [UIImage new]
forBarMetrics: UIBarMetricsDefault];
[UINavigationBar appearance].shadowImage = [UIImage new];
Below image has the explanation (iOS7 NavigationBar):
And check this SO question: iOS7 - Change UINavigationBar border color
Solution 5
The swift way to do it:
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .any, barMetrics: .default)
UINavigationBar.appearance().shadowImage = UIImage()
Szymon Kuczur
Updated on February 02, 2022Comments
-
Szymon Kuczur over 2 years
I have an app that sometimes needs its navigation bar to blend in with the content.
Does anyone know how to get rid of or to change color of this annoying little bar?
On the image below situation i have - i'm talking about this 1px height line below "Root View Controller"
-
akashivskyy over 10 yearsAs Serhii said, a custom background image has to be set for shadow image to be accepted.
-
SeanK over 10 yearsFor keeping the bar translucent I needed to change view.bounds.size.height == 0.5 to view.bounds.size.height == 1.0 but other than that everything worked great. Thanks.
-
SeanK over 10 yearsAn update to my earlier comment: the height needs to be 0.5 for retina devices but 1.0 for non-retina. I see you've change your condition to be <= 1.0 so that covers it.
-
cleverbit over 9 yearsYou can also just set the view of the
UINavigationBar
property:clipsToBounds = YES
-
Mahdi Yusuf over 9 yearsdo this in your AppDelegate.
-
romeouald over 9 years@richarddas
clipsToBounds = YES
works like a charm! Thanks! -
Christian Gossain about 9 yearsThe clipsToBounds doesn't always work for some layouts. This answer worked perfect for me. Only I created a UINavigationBar subclass and used the above code to hide the shadow image in the -layoutSubview methods. Thanks!
-
Jun about 9 yearsThe status bar area is also clipped.
-
Dănuț Mihai Florian almost 9 yearsThanks James! I can't understand why someone down voted your answer.
-
Vlad almost 9 yearsJust to note I had problem where my iOS top status bar become translucent and I could see my table view scrolling behind the UINavigationBar. I fixed this by setting setTranslucent = NO.
-
sudo make install almost 9 yearsIt's pretty rare to get this far down the list before finding the sleekest answer. +1!
-
Axort almost 9 yearsHi guys! Do you know if this is 'App Store safe'? Thanks!
-
Alvivi over 8 years@NunoGonçalves, you can think about
flatAssociatedObjectKey
as an unique int (treated as pointer) to identify your associated object. Here is defined by the memory address of a private var. I updated the response to add this var. See nshipster.com/associated-objects for more info. -
user365314 over 8 yearsIt hides the whole background of the UINavigationBar tho :/
-
Akshay over 8 yearsGreat answer... Saved my day _/\_
-
Alessandro Ornano over 8 yearsif you need it, you can also adding: self.navigationController.navigationBar.translucent = false self.navigationController.navigationBar.clipsToBounds = false self.navigationController.navigationBar.shadowImage = UIImage() self.navigationController.navigationBar.backgroundColor = UIColor.blueColor()
-
ZYiOS over 8 yearsGood solution but works only when navigation bar is set
translucent
to false -
user3344977 over 8 yearsThis is the cleanest solution and best way to accomplish this. If you don't have to support < iOS 8, there's no reason not to use this answer. Thanks.
-
PeiweiChen about 8 yearsThank you! This one should be the answer.
-
vikzilla about 8 yearsWorks great. I set it in storyboard too so didn't even need any code.
-
TomSawyer about 8 yearsAnd it removes the background color also.
-
TomSawyer about 8 yearsWrong, it hides the whole background too!
-
TomSawyer about 8 yearsIt works with navigationBar but doesn't work with uitoolbar
-
Vegard about 8 yearsDoing this gives you a very tiny white line instead of the standard shadow.
-
Tommy K almost 8 yearsHi, new to iOS and trying to teach myself. How do I use the extension? I have a view controller file and I put these extensions in it outside of the class scope. But then how do I call hide/showHairline()? Don't really understand how to use extensions but its used for so many solutions, but I just don't understand how they are implemented in the actual code
-
tf.alves almost 8 yearsThe extensions adds functionality to your existing classes. Any extended class, structure, enum, etc, will have these new features available to you whenever you need to use them. See more here: developer.apple.com/library/ios/documentation/Swift/Conceptual/…
-
Tommy K almost 8 yearshm so I should just be able to use
UINavigationController().navigationBar/toolbar.hide/showBottomHairline()
then no? I'm trying this but to no avail. Am I not understanding correctly? -
JoeGalind almost 8 years+1 Of all the answers, this is what finally worked for me. It didn't mess up the status bar as other answers, and it addresses the problem of changing only one of the navigation controller bars, not all the navigation bars in the project.
-
Arpit B Parekh over 7 yearsIIs it compulsory to have NavigationBarBackgound image ?
-
xi.lin over 7 yearsIn iOS 10 it seems that when
viewWillAppear
is called we cannot getshadowImageView
-
Vakas over 7 yearsI’m on Xcode 8 and developer for > iOS 8 and none of the above worked for me except this one.
-
Christoph over 7 yearsThis sets it global for EVERY nav bar in your code base ... most of the times not what you want.
-
cloudcal over 7 yearsAlso on XCode 8 and > iOS 8. This is the only answer that worked for me.
-
Rohan Sanap over 7 yearsDude!!! YOU ROCK!!! YOU ROCK!!! YOU ROCK!!! All cases perfectly answered and awesome solution to each case. This is the best answer. I personally encountered the situation of maintaining transparency! Thank you.
-
Akhrameev over 7 years@RPM Works great in iOS 7,8,9,10. There is the same code for viewControlles's navigation bar in medium for Swift.
-
dmathewwws over 7 yearsNote: you have to set the navigationBar's isTranslucent to false
-
Yongxiang Ruan about 7 yearsIt is very helpful and complete. Thanks
-
badhanganesh about 7 yearsThis one is perfect! Thanks for sharing. :)
-
Vishal Sonawane almost 7 yearsThis is the only short and simple answer which worked for me for iOS 10 and Xcode 8.3.1. Thanks man.
-
Marcelo dos Santos almost 7 yearsObjective-C: self.navigationController.navigationBar.shadowImage = [UIImage new];
-
jfredsilva over 6 yearsObjective-C: [self.navigationController.navigationBar setValue:@(YES) forKeyPath:@"hidesShadow"];
-
Vishnuvardhan over 6 years@jfredsilva Thanks for the code. I will add this snippet for Objective C reference.
-
Hendrix about 6 yearsThis solved my problem for LargeTitles not working well with the previous solutions.
-
Vahid Amiri about 6 yearsWorks just fine on iOS 11.
-
Cons Bulaquena about 6 yearsEasily understandable to the nitty-gritty of UIs!
-
RichAppz almost 6 yearsI can't believe this is still an issue - just came across it again! But this solution is the best possible one at the moment; Thanks @Socheat
-
Gandalf458 almost 6 yearsSwift 4 required: UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default) UINavigationBar.appearance().shadowImage = UIImage()
-
Gandalf458 almost 6 yearsMust be called in AppDelegate in didFinishLaunchingWithOptions
-
Chris Prince over 5 yearsI'm finding with iOS 12 this is not working any more. :(.
-
Shruti Thombre over 5 yearsThis is exactly what i want, Thanks
-
akaralar over 5 yearsIt can't find the hairline on iOS 12, is there a way to do that?
-
Prashant Tukadiya over 5 yearsWorking perfectly !!
-
Jan Erik Schlorf about 5 years
clipsToBounds = YES
will also clip the upper part of the navigation bar, exposing the background of the status bar, which can get problematic if yournavigationBar
has a custom color. -
airowe almost 5 yearsSwift 4.2 version: navigationBar?.setBackgroundImage(UIImage(), for: UIBarPosition.any, barMetrics: UIBarMetrics.default) navigationBar?.shadowImage = UIImage()
-
ttorbik almost 5 yearsWorks great iOS 13
-
Roger Oba over 4 yearsshadowImage and shadowColor aren't documented in
UINavigationBarAppearance
headers!! I'd never find it. Thanks, this solved my issues 100% -
Yogesh Patel over 4 yearsYes it's working fine for me too in iOS 13 thank you so much @glotcha.
-
glotcha over 4 yearsAs of iOS 13 there is a system API to set or remove the shadow UIKit uses shadowImage and the shadowColor property to determine the shadow's appearance. When shadowImage is nil, the bar displays a default shadow tinted according to the value in the shadowColor property. If shadowColor is nil or contains the clearColor color, the bar displays no shadow. For code see my answer below.
-
Hitesh Surani over 4 yearsThis one should be the answer. works like charm in ios 13
-
Argus over 4 years.shadowColor solution:
if #available(iOS 13.0, *) { let appearance = UINavigationBarAppearance() appearance.shadowColor = nil navigationController.navigationBar.standardAppearance = appearance }
-
Ravi about 4 yearsOnly this working for me in iOS 13.3.1 Version iPad.
-
Roman Samoilenko about 4 yearsWhat worked for me was
navigationBar.standardAppearance.shadowColor = .clear
-
alekop almost 4 yearsSetting
scrollEdgeAppearance
doesn't work on iOS 13.5. SettingclipToBounds = true
does, but makes the background color slightly (but noticeably) different from the status bar color, even though I used the default color. UsingstandardAppearance
does remove the separator, and preserves background color. -
Theo Bendixson almost 4 yearsThis isn't robust. Apple could stop using the "hidesShadow" keyPath at any moment, and your app will break as a result
-
yuzer over 3 yearsThe only one that worked for me without any side effects. I'm using Opaque Navigation Bar.
-
andrewlundy over 3 yearsThis is not a good answer. You're not directly accessing the API of a class, and this is subject to App Store rejection because the key path 'hidesShadow' could be removed at any point. If this happens, your app would immediately break. You can do this correctly in iOS 13 or later as followed: navigationBar.standardAppearance.shadowColor = nil
-
Jeffrey Neo almost 3 yearsyour answer will break the setup for
isTranslucent = false
, the background color will be changed. so far only the "to not use" answer is working for me, even in the latest iOS 14.4 -
Eric over 2 yearssetting shadow image to empty worked for Swift5!!