How to remove border of the navigationBar in swift?

IosIphoneSwiftUinavigationbar

Ios Problem Overview


i've been trying to remove the navigationBars border without luck. I've researched and people seem to tell to set shadowImage and BackgroundImage to nil, but this does not work in my case.

My code

    self.navigationController?.navigationBar.barTintColor = UIColor(rgba: "#4a5866")
    self.navigationController?.navigationBar.setBackgroundImage(UIImage(named: ""), forBarMetrics: UIBarMetrics.Default)
    self.navigationController?.navigationBar.shadowImage = UIImage(named: "")

illustration:

enter image description here

Ios Solutions


Solution 1 - Ios

The trouble is with these two lines:

self.navigationController?.navigationBar.setBackgroundImage(UIImage(named: ""), forBarMetrics: UIBarMetrics.Default)
self.navigationController?.navigationBar.shadowImage = UIImage(named: "")

Since you don't have an image with no name, UIImage(named: "") returns nil, which means the default behavior kicks in:

> When non-nil, a custom shadow image to show instead of the default shadow image. For a custom shadow to be shown, a custom background image must also be set with -setBackgroundImage:forBarMetrics: (if the default background image is used, the default shadow image will be used).

You need a truly empty image, so just initialize with UIImage():

self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
self.navigationController?.navigationBar.shadowImage = UIImage()

Solution 2 - Ios

Swift 4 & Swift 5

Removing border:

self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for:.default)
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.layoutIfNeeded()

Restoring border:

self.navigationController?.navigationBar.setBackgroundImage(nil, for:.default)
self.navigationController?.navigationBar.shadowImage = nil
self.navigationController?.navigationBar.layoutIfNeeded()

Solution 3 - Ios

With Swift 2 you can do it this way:

AppDelegate file

Inside func application(..., didFinishLaunchingWithOptions launchOptions:...)

UINavigationBar.appearance().shadowImage = UIImage()
UINavigationBar.appearance().setBackgroundImage(UIImage(), forBarMetrics: .Default)

for Swift 3:

UINavigationBar.appearance().shadowImage = UIImage()
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)

Solution 4 - Ios

Just write this in the extension of UINavigationBar

extension UINavigationBar {

    func shouldRemoveShadow(_ value: Bool) -> Void {
        if value {
            self.setValue(true, forKey: "hidesShadow")
        } else {
            self.setValue(false, forKey: "hidesShadow")
        }
    }
}

And in your viewController...

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    self.navigationController?.navigationBar.shouldRemoveShadow(true)        
}

And to get this undone for any viewController, just pass false.

Solution 5 - Ios

this will remove the shadow image altogether

for parent in self.navigationController!.navigationBar.subviews {
 for childView in parent.subviews {
     if(childView is UIImageView) {
         childView.removeFromSuperview()
     }
 }
}

Solution 6 - Ios

Swift 5

When using setBackgroundImage / shadowImage to hide the hairline, there's a slight delay. This method removes the delay. Credit to Chameleon Framework. This is the method they use (in ObjC)


extension UINavigationController {
    func hideHairline() {
        if let hairline = findHairlineImageViewUnder(navigationBar) {
            hairline.isHidden = true
        }
    }
    func restoreHairline() {
        if let hairline = findHairlineImageViewUnder(navigationBar) {
            hairline.isHidden = false
        }
    }
    func findHairlineImageViewUnder(_ view: UIView) -> UIImageView? {
        if view is UIImageView && view.bounds.size.height <= 1.0 {
            return view as? UIImageView
        }
        for subview in view.subviews {
            if let imageView = self.findHairlineImageViewUnder(subview) {
                return imageView
            }
        }
        return nil
    }
}

Solution 7 - Ios

let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithTransparentBackground()

Solution 8 - Ios

Set barStyle to .Black before setting the tint:

self.navigationController?.navigationBar.translucent = false
self.navigationController?.navigationBar.barStyle = .Black
self.navigationController?.navigationBar.barTintColor = UIColor.blueColor()

Solution 9 - Ios

Luca Davanzo's answer is great, but it does not work in iOS 10. I altered it to work in iOS 10 and below.

for parent in navigationController!.view.subviews {
    for child in parent.subviews {
        for view in child.subviews { 
            if view is UIImageView && view.frame.height == 0.5 {
                view.alpha = 0
            }
        }
    }
}

You can also extend UINavigationController and call this off of that. removeFromSuperview() on the line will not work on iOS 10, so I just set the alpha to 0 so this one call is compatible everywhere.

Solution 10 - Ios

To remove border from UINavigationBar in Swift 3+, use:

UINavigationBar.appearance().shadowImage = UIImage()
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)
UINavigationBar.appearance().isTranslucent = false

Solution 11 - Ios

Only this worked for me,

self.navigationController?.navigationBar.shadowImage = UIImage()

Ref

Solution 12 - Ios

Swiftier method of Jack Chen:

extension UINavigationController {

    var isHiddenHairline: Bool {
        get {
            guard let hairline = findHairlineImageViewUnder(navigationBar) else { return true }
            return hairline.isHidden
        }
        set {
            if let hairline = findHairlineImageViewUnder(navigationBar) {
                hairline.isHidden = newValue
            }
        }
    }

    private func findHairlineImageViewUnder(_ view: UIView) -> UIImageView? {
        if view is UIImageView && view.bounds.size.height <= 1.0 {
            return view as? UIImageView
        }

        for subview in view.subviews {
            if let imageView = self.findHairlineImageViewUnder(subview) {
                return imageView
            }
        }

        return nil
    }
}

Using:

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        navigationController?.isHiddenHairline = true
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        navigationController?.isHiddenHairline = false
    }

Solution 13 - Ios

for swift 3

in viewDidLoad method

navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
navigationController?.navigationBar.shadowImage = UIImage()

Solution 14 - Ios

Updated for Swift 4 in case someone is wondering

navigationBar.shadowImage = UIImage()
navigationBar.backIndicatorImage = UIImage()

It's even less verbose now.

Solution 15 - Ios

The accepted answer worked for me but I noticed when I wanted the shadow image to reappear when popping back or pushing forward to another vc there was a noticeable blink in the navigation bar.

Using this method navigationController?.navigationBar.setValue(true, forKey: "hidesShadow") in viewWillAppear the shadow bar is hidden in the current visible view controller.

Using these 2 methods

navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
navigationController?.navigationBar.setValue(false, forKey: "hidesShadow")

in viewWillDisappear the blink still happens but only when the shadow image reappears and not the navigation bar itself.

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    
    // 1. hide the shadow image in the current view controller you want it hidden in
    navigationController?.navigationBar.setValue(true, forKey: "hidesShadow")
    navigationController?.navigationBar.layoutIfNeeded()
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(true)
    
    // 2. show the shadow image when pushing or popping in the next view controller. Only the shadow image will blink
    navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
    navigationController?.navigationBar.setValue(false, forKey: "hidesShadow")
    navigationController?.navigationBar.layoutIfNeeded()
}

Solution 16 - Ios

If you want to remove only the bottom line and keep the solid color of navigationBar, add these lines of code in viewDidLoad: Swift 3, 4:

navigationController?.navigationBar.shadowImage = UIImage()
navigationController?.navigationBar.isTranslucent = false

Peace!

Solution 17 - Ios

This is the way if you want to do it without changing the background color:

// Remove the border ImageView from the NavigationBar background
func hideBottomBorder() {
    for view in navigationBar.subviews.filter({ NSStringFromClass($0.dynamicType) == "_UINavigationBarBackground" }) as [UIView] {
        if let imageView = view.subviews.filter({ $0 is UIImageView }).first as? UIImageView {
            imageView.removeFromSuperview()
        }
    }
}

NOTE: This might crash on a production app. Apparently the NavigationBar doesn't like its view disappearing

Solution 18 - Ios

in your custom navigationController add these lines:

self.navigationBar.setBackgroundImage(UIImage(), for:.default)
self.navigationBar.shadowImage = UIImage()
self.navigationBar.layoutIfNeeded()

#Important Note# the last line is important if you use the first line viewDidLoad() method because navigationController should redraw nav bar but easily you can use this without layoutIfNeeded() in the viewWillAppear() method before it draws the nav bar

Solution 19 - Ios

Within AppDelegate, this has globally changed the format of the NavBar and removes the bottom line/border:

 func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    UINavigationBar.appearance().setBackgroundImage(UIImage(), forBarPosition: UIBarPosition.Any, barMetrics: UIBarMetrics.Default)
    UINavigationBar.appearance().shadowImage = UIImage()
    UINavigationBar.appearance().tintColor = UIColor.whiteColor()
    UINavigationBar.appearance().barTintColor = UIColor.redColor()
    UINavigationBar.appearance().translucent = false
    UINavigationBar.appearance().clipsToBounds = false
    //UINavigationBar.appearance().backgroundColor = UIColor.redColor()
    UINavigationBar.appearance().titleTextAttributes = [NSFontAttributeName : (UIFont(name: "FONT NAME", size: 18))!, NSForegroundColorAttributeName: UIColor.whiteColor()] }

Haven't managed to implement anything different on a specific VC, but this will help 90% of people

Solution 20 - Ios

for the swift3 you should write slightly different way:

 self.navigationController?.navigationBar.setBackgroundImage(UIImage(),
    for: UIBarMetrics.default)
   self.navigationController?.navigationBar.shadowImage = UIImage()

Solution 21 - Ios

This is a streamlined version of Gaurav Chandarana's answer.

extension UINavigationBar {
    
    func hideShadow(_ value: Bool = true) {
        setValue(value, forKey: "hidesShadow")
    }
}

Solution 22 - Ios

App delegate

UINavigationBar.appearance().setBackgroundImage(UIImage(), for: UIBarMetrics.default)
UINavigationBar.appearance().shadowImage = UIImage()

Solution 23 - Ios

I use this code in AppDelegate's didFinishLaunchingWithOptions method to reach it in whole app:

 let barAppearance = UINavigationBar.appearance()
    
 if #available(iOS 13, *) {
     let appearance = UINavigationBarAppearance()
     appearance.configureWithTransparentBackground()
     barAppearance.standardAppearance = appearance
     barAppearance.scrollEdgeAppearance = appearance
 } else {
     barAppearance.setBackgroundImage(UIImage(), for: UIBarPosition.any, barMetrics: UIBarMetrics.defaultPrompt)
     barAppearance.shadowImage = UIImage()
 }

Solution 24 - Ios

For iOS 13+:

let appearance = UINavigationBarAppearance()
appearance.shadowColor = .clear

Assign this appearance to the UINavigationBar:

navigationController?.navigationBar.standardAppearance = appearance
navigationController?.navigationBar.scrollEdgeAppearance = appearance
navigationController?.navigationBar.compactAppearance = appearance

Setting shadowImage = UIImage() didn't work for me.

Solution 25 - Ios

The border line is an UIImageView and removing a subview which is an imageView will remove barButtonItems with UIImageView. Below code will help you remove it. Hope this helps someone who faced an issue like me.

for parent in self.navigationController!.navigationBar.subviews {
        for childView in parent.subviews {
            if childView.frame.height == 0.5 {
                childView.removeFromSuperview()
            }
        }
    }

The border UIImageView is only 0.5 in height so this code removes only that.

Solution 26 - Ios

this is the answer in swift 3 base of Nate Cook answer

   self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
    self.navigationController?.navigationBar.shadowImage = UIImage()

Solution 27 - Ios

iOS 11 and Swift 4 You should try following if you want to remove the border but don't to make the navigitonbar translucent
self.navigationBar.shadowImage = UIImage()

Solution 28 - Ios

Swift 11.4

I was customizing UINavigationController so accessing through self.navigationController?.navigationBar didn't work for me, but using direct in:

self.navigationBar.setBackgroundImage(UIImage(), for:.default)
self.navigationBar.shadowImage = UIImage()
self.navigationBar.layoutIfNeeded()

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPeter PikView Question on Stackoverflow
Solution 1 - IosNate CookView Answer on Stackoverflow
Solution 2 - IosSazzad Hissain KhanView Answer on Stackoverflow
Solution 3 - IosJorge CasariegoView Answer on Stackoverflow
Solution 4 - IosGaurav ChandaranaView Answer on Stackoverflow
Solution 5 - IosSteve PayneView Answer on Stackoverflow
Solution 6 - IosJack ChenView Answer on Stackoverflow
Solution 7 - IosGIJoeCodesView Answer on Stackoverflow
Solution 8 - IosgpblView Answer on Stackoverflow
Solution 9 - IosDavid BaezView Answer on Stackoverflow
Solution 10 - Iosreza_khalafiView Answer on Stackoverflow
Solution 11 - IosMohammad Zaid PathanView Answer on Stackoverflow
Solution 12 - IosMickael BelhassenView Answer on Stackoverflow
Solution 13 - IosGulzView Answer on Stackoverflow
Solution 14 - IosMauricio ChirinoView Answer on Stackoverflow
Solution 15 - IosLance SamariaView Answer on Stackoverflow
Solution 16 - IosMihail SalariView Answer on Stackoverflow
Solution 17 - IosYariv NissimView Answer on Stackoverflow
Solution 18 - IosMr ZeeView Answer on Stackoverflow
Solution 19 - IosDavid WestView Answer on Stackoverflow
Solution 20 - IosChetan DobariyaView Answer on Stackoverflow
Solution 21 - IosScott GardnerView Answer on Stackoverflow
Solution 22 - IosSrinivasan_iOSView Answer on Stackoverflow
Solution 23 - IosDmytro YashchenkoView Answer on Stackoverflow
Solution 24 - IosDrewView Answer on Stackoverflow
Solution 25 - IosbachmanView Answer on Stackoverflow
Solution 26 - IosAlan View Answer on Stackoverflow
Solution 27 - IosBilalReffasView Answer on Stackoverflow
Solution 28 - IosNeylor BagagiView Answer on Stackoverflow