¿Cómo eliminar el borde de la barra de navegación en Swift?

131

He estado tratando de eliminar el borde de NavigationBars sin suerte. He investigado y la gente parece decirle que establezca shadowImage y BackgroundImage en nulo, pero esto no funciona en mi caso.

Mi código

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

ilustración:

ingrese la descripción de la imagen aquí

Peter Pik
fuente

Respuestas:

309

El problema es con estas dos líneas:

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

Como no tiene una imagen sin nombre, UIImage(named: "")devuelve nil, lo que significa que el comportamiento predeterminado entra en juego:

Cuando no es nulo, se muestra una imagen de sombra personalizada en lugar de la imagen de sombra predeterminada. Para que se muestre una sombra personalizada, también se debe establecer una imagen de fondo personalizada con -setBackgroundImage: forBarMetrics: (si se usa la imagen de fondo predeterminada, se usará la imagen de sombra predeterminada).

Necesita una imagen verdaderamente vacía, así que simplemente inicialice con UIImage():

self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
self.navigationController?.navigationBar.shadowImage = UIImage()
Nate Cook
fuente
2
Esta respuesta realmente funciona. Porque si usa la respuesta aceptada (código), se eliminará la barra de herramientas imageViews a.
Sergey Krasiuk
1
Esta debería ser la respuesta aceptada. También funciona cuando se configura desde UINavigationBar.appearance ()
Heinrisch
1
Esta debería ser la respuesta aceptada para Swift 3. La respuesta aceptada funcionó para mí en Swift 2, pero no en Swift 3
ColinMasters
1
para swift3, debe escribir de manera ligeramente diferente: self.navigationController? .navigationBar.setBackgroundImage (UIImage (), para: UIBarMetrics.default) self.navigationController? .navigationBar.shadowImage = UIImage ()
Chetan Dobariya
55
Este método entra en conflicto con el título grande en iOS 11
SteffenK
54

Swift 4 y Swift 5

Eliminar borde:

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

Restaurando borde:

self.navigationController?.navigationBar.setBackgroundImage(nil, for:.default)
self.navigationController?.navigationBar.shadowImage = nil
self.navigationController?.navigationBar.layoutIfNeeded()
Sazzad Hissain Khan
fuente
2
Respuesta perfecta :)
PJR
¿Necesitamos layoutIfNeeded () aquí?
korgx9
1
Sí korgx9, lo necesitamos. De lo contrario, no cambiará el color hasta el próximo sorteo.
Sazzad Hissain Khan
37

esto eliminará la imagen de la sombra por completo

for parent in self.navigationController!.navigationBar.subviews {
 for childView in parent.subviews {
     if(childView is UIImageView) {
         childView.removeFromSuperview()
     }
 }
}
Steve Payne
fuente
1
¿Podrías dar más detalles?
Kmeixner
1
También para mí funciona esta solución, mientras que la respuesta de @Nate Cook no funcionó. : S
Luca Davanzo
2
Santo sheist !! Después de toda la búsqueda, esto es lo ÚNICO que ha funcionado.
Tuan Anh Vu
funciona, pero también tengo un ícono de menú en la barra de navegación y desapareció: / solo quiero que se borre el borde. AYUDA: /
Stephy Samaniego
Esto funcionó para mí, pero después de presionar el nuevo ViewController, elimina la línea de allí a. ¿Cómo puedo evitarlo?
Anirudha Mahale
36

Con Swift 2 puedes hacerlo de esta manera:

Archivo AppDelegate

Aplicación de funciones internas (..., didFinishLaunchingWithOptions launchOptions: ...)

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

para Swift 3:

UINavigationBar.appearance().shadowImage = UIImage()
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)
Jorge Casariego
fuente
Respuesta correcta.
Ed.
Esta es la respuesta integral!
madeny
Es mejor escribir valores predeterminados útiles en Appdelegate que escribirlos en lugares extraños. Respuesta correcta :)
Md Rais
35

Simplemente escriba esto en la extensión de UINavigationBar

extension UINavigationBar {

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

Y en tu opinión, Controlador ...

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

Y para deshacer esto para cualquier viewController, simplemente pase falso.

Gaurav Chandarana
fuente
Esto funciona muy bien PERO se esconde si para TODAS las vcs en la pila de navegación. Si lo usa en vc1 y vc1 puede empujar a vc2, también estará oculto en vc2. Para mostrar la sombra en vc2, deberá establecerla en false en viewDidLoad. El problema es que cuando vuelves a vc1 se mostrará de nuevo porque se restableció en vc2. Tienes que usar la lógica para ir y venir, lo que podría no valer la pena. Sin embargo, si no desea que la imagen de la sombra se muestre en ninguna vcs, esta es la forma más fácil de hacerlo
Lance Samaria, el
Digamos que tenemos una pila de viewControllers con 5 viewControllers (y hemos ocultado la sombra en el primero). Ahora, solo para el 3er viewController, NO queremos ocultar la sombra. Entonces, llamaré a ese método con FALSE en viewWillAppear y con TRUE en viewWillDisappear del 3rd viewController. ¡Eso es todo!
Gaurav Chandarana
eres absolutamente correcto, buen pensamiento! No creo que haya rechazado tu respuesta porque es muy sucinta y eficiente, también voté. Lo uso para eliminarlo y la barra de navegación para mensajes de error. El problema que encontré fue al eliminarlo en vc1 pero mostrarlo vc2, pero si hubo un error en vc2, entonces eliminarlo en viewWillDisappear podría no funcionar. Pero, de nuevo, es una situación muy singular. Me gusta la idea viewWillDisappear para uso general de casos y debe agregarla a su respuesta. ¡Independientemente de que su código funcione y es una manera fácil de eliminar la sombra! 👍🏿👍🏿
Lance Samaria
Funciona de maravilla. ¿Solo quería asegurarme de que esto no sea una configuración privada?
inokey
2
Esta es una excelente respuesta! Agregué una respuesta que simplifica el código.
Scott Gardner
13

Establecer barStylea .Blackantes de ajustar el tinte:

self.navigationController?.navigationBar.translucent = false
self.navigationController?.navigationBar.barStyle = .Black
self.navigationController?.navigationBar.barTintColor = UIColor.blueColor()
gpbl
fuente
¿Es un poco aleatorio que esto realmente funcione? o estoy pensando demasiado?
Joe
@joe bueno, está funcionando aquí :-) ¿no te funciona?
gpbl
esa es la cosa, sí funciona. Me pregunto si hay una explicación de por qué cambiar el barStyle a negro, luego cambia todo el barTintColor a azul :)
Joe
quizás configurándolo en negro y opaco, desactiva algunas capas / vista en la
barra de
Intenté usar esto, y elimina la línea de fondo, sin embargo, si usa un tinte de barra de blanco, el título no es visible: /
RileyDev
11

Swift 5

Cuando se usa setBackgroundImage / shadowImage para ocultar la rayita, hay un ligero retraso. Este método elimina el retraso. Crédito a Chameleon Framework . Este es el método que usan (en 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
    }
}
Jack Chen
fuente
1
FWIW, esta es la única solución que funcionó para mí en iOS 13.4 ...
kevinstueber
9

La respuesta de Luca Davanzo es excelente, pero no funciona en iOS 10. Lo modifiqué para que funcione en iOS 10 y versiones posteriores.

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
            }
        }
    }
}

También puede extender UINavigationController y cancelar esto. removeFromSuperview()en la línea no funcionará en iOS 10, así que configuré el alfa en 0 para que esta llamada sea compatible en todas partes.

David Baez
fuente
Buena captura, ¿alguna forma de mostrar / ocultar la sombra en algunos controles de vista mientras navegas?
Ashkan.H
Debería verificar las alturas que tienen a height >= 1.0. En los modelos de iPhone que tienen una pantalla de retina 3x (por ejemplo, 8 Plus, XR ...) la línea del cabello tiene una altura de 0,33.
fl034
7

Para eliminar el borde de UINavigationBar en Swift 3+, use:

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

para swift 3

en viewDidLoadmétodo

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

Solo esto funcionó para mí

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

Árbitro

Mohammad Zaid Pathan
fuente
4

Actualizado para Swift 4 en caso de que alguien se pregunte

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

Es aún menos detallado ahora.

Mauricio Chirino
fuente
2

Este es el camino si desea hacerlo sin cambiar el color de fondo:

// 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()
        }
    }
}

NOTA: Esto podría bloquearse en una aplicación de producción. Aparentemente, a NavigationBar no le gusta que su vista desaparezca

Yariv Nissim
fuente
2

La respuesta aceptada funcionó para mí, pero me di cuenta de cuándo quería que reapareciera la imagen de la sombra al aparecer hacia atrás o avanzar hacia otra vc. Hubo un parpadeo notable en la barra de navegación.

Al usar este método navigationController?.navigationBar.setValue(true, forKey: "hidesShadow") en viewWillAppear, la barra de sombra está oculta en el controlador de vista visible actual.

Usando estos 2 métodos

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

en viewWillDisappear el parpadeo todavía ocurre pero solo cuando reaparece la imagen de sombra y no la barra de navegación en sí.

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()
}
Lance Samaria
fuente
1

para el swift3 deberías escribir de forma ligeramente diferente:

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

Esta es una versión simplificada de la respuesta de Gaurav Chandarana .

extension UINavigationBar {

    func hideShadow(_ value: Bool = true) {
        setValue(value, forKey: "hidesShadow")
    }
}
Scott Gardner
fuente
1

Delegado de aplicaciones

UINavigationBar.appearance().setBackgroundImage(UIImage(), for: UIBarMetrics.default)
UINavigationBar.appearance().shadowImage = UIImage()
CSE 1994
fuente
1

Si desea eliminar solo la línea inferior y mantener el color sólido de la barra de navegación, agregue estas líneas de código en viewDidLoad: Swift 3, 4:

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

¡Paz!

Mihail Salari
fuente
0

La línea de borde es un UIImageView y al eliminar una subvista que es un imageView se eliminarán barButtonItems con UIImageView. El siguiente código lo ayudará a eliminarlo. Espero que esto ayude a alguien que se enfrentó a un problema como yo.

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

El borde UIImageView tiene solo 0.5 de altura, por lo que este código solo elimina eso.

bachman
fuente
Esto me causó accidentes. Creo que las vistas parent y childView deben desenvolverse en caso de que sean nulas antes de verificar cada una. Sin embargo, estoy usando un UINavigationController personalizado, por lo que este podría no ser el caso para otros usuarios con una barra estándar.
Natalia
0

Dentro de AppDelegate , esto ha cambiado globalmente el formato de la barra de navegación y elimina la línea inferior / borde:

 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()] }

No he logrado implementar nada diferente en un VC específico, pero esto ayudará al 90% de las personas

David West
fuente
UINavigationBar.appearance (). BackgroundColor = UIColor.redColor () no es necesario.
sabiland
0

esta es la respuesta en la base 3 rápida de la respuesta de Nate Cook

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

iOS 11 y Swift 4 Debe intentar seguir si desea eliminar el borde pero no hacer que la barra de navegación sea translúcida
self.navigationBar.shadowImage = UIImage()

BilalReffas
fuente
0

en su NavigationController personalizado agregue estas líneas:

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

Nota IMPORTANTE

la última línea es importante si usa el método viewDidLoad () de la primera línea porque navigationController debería volver a dibujar la barra de navegación, pero puede usarlo fácilmente sin layoutIfNeeded () en el método viewWillAppear () antes de dibujar la barra de navegación

Señor zee
fuente
0

Método más rápido de 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
    }
}

Utilizando:

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

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        navigationController?.isHiddenHairline = false
    }
Mickael Belhassen
fuente
0
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithTransparentBackground()
GIJoeCodes
fuente