Jak szybko usunąć obramowanie paska nawigacji?

131

Próbowałem usunąć obramowanie NavigationBars bez powodzenia. Zbadałem i ludzie wydają się mówić, aby ustawić shadowImage i BackgroundImage na zero, ale to nie działa w moim przypadku.

Mój kod

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

ilustracja:

wprowadź opis obrazu tutaj

Peter Pik
źródło

Odpowiedzi:

309

Problem polega na tych dwóch liniach:

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

Ponieważ nie masz obrazu bez nazwy, UIImage(named: "")zwraca nil, co oznacza, że ​​domyślne zachowanie zaczyna działać :

Gdy wartość jest różna, zamiast domyślnego obrazu cienia wyświetlany jest niestandardowy obraz cienia. Aby niestandardowy cień był wyświetlany, niestandardowy obraz tła musi być również ustawiony za pomocą -setBackgroundImage: forBarMetrics: (jeśli używany jest domyślny obraz tła, zostanie użyty domyślny obraz cienia).

Potrzebujesz naprawdę pustego obrazu, więc po prostu zainicjuj UIImage():

self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
self.navigationController?.navigationBar.shadowImage = UIImage()
Nate Cook
źródło
2
Ta odpowiedź naprawdę działa. Ponieważ jeśli użyjesz zaakceptowanej odpowiedzi (kodu), jego pasek narzędzi usuwania imageViews do.
Sergey Krasiuk
1
To powinna być akceptowana odpowiedź. Działa również podczas ustawiania z UINavigationBar.appearance ()
Heinrisch.
1
To powinna być zaakceptowana odpowiedź dla Swift 3. Zaakceptowana odpowiedź zadziałała dla mnie w Swift 2, ale nie w Swift 3
ColinMasters
1
dla swift3 należy napisać nieco inaczej: self.navigationController? .navigationBar.setBackgroundImage (UIImage (), dla: UIBarMetrics.default) self.navigationController? .navigationBar.shadowImage = UIImage ()
Chetan Dobariya
5
Ta metoda koliduje z dużym tytułem w iOS 11
SteffenK
53

Swift 4 i Swift 5

Usuwanie obramowania:

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

Przywracanie granicy:

self.navigationController?.navigationBar.setBackgroundImage(nil, for:.default)
self.navigationController?.navigationBar.shadowImage = nil
self.navigationController?.navigationBar.layoutIfNeeded()
Sazzad Hissain Khan
źródło
2
Doskonała odpowiedź :)
PJR
Czy potrzebujemy tutaj layoutIfNeeded ()?
korgx9
1
Tak, korgx9, potrzebujemy tego. W przeciwnym razie nie zmieni koloru do następnego losowania.
Sazzad Hissain Khan
37

spowoduje to całkowite usunięcie obrazu cienia

for parent in self.navigationController!.navigationBar.subviews {
 for childView in parent.subviews {
     if(childView is UIImageView) {
         childView.removeFromSuperview()
     }
 }
}
Steve Payne
źródło
1
Czy mógłbyś to rozwinąć?
Kmeixner
1
U mnie też działa to rozwiązanie, podczas gdy odpowiedź @Nate Cook nie działa. : S
Luca Davanzo
2
Holy sheist !! Po tych wszystkich poszukiwaniach jest to JEDYNA rzecz, która się sprawdziła.
Tuan Anh Vu
to działa, ale mam też ikonę menu na pasku nawigacyjnym i zniknęła: / chcę tylko usunąć obramowanie. POMOC: /
Stephy Samaniego
To zadziałało, ale po wypchnięciu nowego ViewController usuwa stamtąd wiersz do. Jak mogę temu zapobiec?
Anirudha Mahale
36

Dzięki Swift 2 możesz to zrobić w następujący sposób:

Plik AppDelegate

Wewnątrz aplikacji func (..., didFinishLaunchingWithOptions launchOptions: ...)

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

dla Swift 3:

UINavigationBar.appearance().shadowImage = UIImage()
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)
Jorge Casariego
źródło
Poprawna odpowiedź.
wyd.
To jest wyczerpująca odpowiedź!
madeny
Lepiej jest pisać takie przydatne wartości domyślne w Appdelegate niż zapisywać je w dziwnych miejscach. Dobra odpowiedź :)
Md Rais
35

Po prostu napisz to w rozszerzeniu UINavigationBar

extension UINavigationBar {

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

A w Twoim widoku Kontroler ...

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

Aby cofnąć to działanie dla dowolnego elementu viewController, po prostu przekaż wartość false.

Gaurav Chandarana
źródło
Działa to świetnie, ALE ukrywa się, jeśli dla WSZYSTKICH vcs na stosie nawigacyjnym. Jeśli używasz go w vc1, a vc1 może wypchnąć do vc2, zostanie również ukryty na vc2. Aby pokazać cień w vc2, musisz ustawić go na false w viewDidLoad. Problem polega na tym, że gdy wrócisz do vc1, pojawi się ponownie, ponieważ został zresetowany w vc2. Musisz użyć logiki, aby iść tam iz powrotem, co może nie być tego warte. Jeśli jednak nie chcesz, aby obraz cienia w ogóle był wyświetlany na jakimkolwiek vcs, to jest to najłatwiejszy sposób
Lance Samaria
Powiedzmy, że mamy stos viewControllers z 5 viewControllers (i ukryliśmy cień w pierwszym). Teraz tylko dla trzeciego viewController, ja NIE CHCEMY ukryć cienia. Więc wywołam tę metodę z FALSE w viewWillAppear i TRUE w viewWillDisappear z trzeciego viewController. To wszystko!
Gaurav Chandarana
Twoje absolutnie poprawne, dobre myślenie! Nie myśl, że podniosłem twoją odpowiedź, ponieważ jest bardzo zwięzła i skuteczna, również ją zagłosowałem. Używam go, aby go usunąć i navBar dla komunikatów o błędach. Problem, który znalazłem, dotyczył usuwania go w vc1, ale pokazania go jako vc2, ale jeśli wystąpił błąd w vc2, usunięcie go w viewWillDisappear może nie działać. Ale znowu jest to bardzo wyjątkowa sytuacja. Podoba mi się pomysł viewWillDisappear do ogólnego użytku i powinieneś dodać go do swojej odpowiedzi. Niezależnie od tego, czy Twój kod działa i jest to łatwy sposób na usunięcie cienia! 👍🏿👍🏿
Lance Samaria,
Działa jak marzenie. Chciałeś się tylko upewnić, że to nie są ustawienia prywatne?
inokey
2
To doskonała odpowiedź! Dodałem odpowiedź, która usprawnia kod.
Scott Gardner
13

Ustaw barStylena .Blackprzed ustawieniem odcienia:

self.navigationController?.navigationBar.translucent = false
self.navigationController?.navigationBar.barStyle = .Black
self.navigationController?.navigationBar.barTintColor = UIColor.blueColor()
gpbl
źródło
czy to trochę przypadkowe, że to faktycznie działa? czy za dużo się zastanawiam?
joe
@joe cóż, tutaj działa :-) czy to nie działa dla Ciebie?
gpbl
o to chodzi, to działa. Zastanawiam się tylko, czy istnieje wyjaśnienie, dlaczego zmieniam styl paska na czarny, a następnie zmienia kolor całego paska na niebieski :)
joe
może ustawiając go na czarny i nieprzezroczysty, wyłącza niektóre warstwy / widok na
pasku
Próbowałem tego użyć i usuwa to dolną linię, jednak jeśli
użyję
11

Szybki 5

Podczas używania setBackgroundImage / shadowImage do ukrycia linii włosów występuje niewielkie opóźnienie. Ta metoda usuwa opóźnienie. Podziękowania dla Chameleon Framework . To jest metoda, której używają (w 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
źródło
1
FWIW, to jedyne rozwiązanie, które działało dla mnie na iOS 13.4 ...
kevinstueber
9

Odpowiedź Luca Davanzo jest świetna, ale nie działa w iOS 10. Zmieniłem ją, żeby działała w iOS 10 i niższych.

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

Możesz także rozszerzyć UINavigationController i wywołać to z tego. removeFromSuperview()na linii nie będzie działać na iOS 10, więc po prostu ustawiłem alfa na 0, więc to jedno połączenie jest kompatybilne wszędzie.

David Baez
źródło
Niezły chwyt, jakikolwiek sposób na pokazanie / ukrycie cienia w niektórych kontrolerach widoku podczas nawigacji?
Ashkan.H
Powinieneś raczej sprawdzić wysokości, które mają height >= 1.0. W modelach iPhone'a z 3-krotnym ekranem siatkówkowym (np. 8 Plus, XR ...) linia włosów ma wysokość 0,33.
fl034
7

Aby usunąć obramowanie z UINavigationBar w Swift 3+, użyj:

UINavigationBar.appearance().shadowImage = UIImage()
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)
UINavigationBar.appearance().isTranslucent = false
reza_khalafi
źródło
5

dla szybkiego 3

w viewDidLoadmetodzie

navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
navigationController?.navigationBar.shadowImage = UIImage()
Gulz
źródło
4

Tylko to działało dla mnie,

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

Nr ref

Mohammad Zaid Pathan
źródło
4

Zaktualizowano dla Swift 4 na wypadek, gdyby ktoś się zastanawiał

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

Teraz jest jeszcze mniej gadatliwy.

Mauricio Chirino
źródło
2

Oto sposób, jeśli chcesz to zrobić bez zmiany koloru tła:

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

UWAGA: może to spowodować awarię w aplikacji produkcyjnej. Najwyraźniej pasek nawigacji nie lubi znikać widoku

Yariv Nissim
źródło
2

Zaakceptowana odpowiedź zadziałała dla mnie, ale zauważyłem, że gdy chciałem, aby obraz cienia pojawił się ponownie po cofnięciu się lub przesunięciu do przodu do innego vc, zauważalne było mrugnięcie na pasku nawigacyjnym.

Korzystając z tej metody navigationController?.navigationBar.setValue(true, forKey: "hidesShadow") w viewWillAppear pasek cienia jest ukryty w kontrolerze bieżącego widocznego widoku.

Korzystanie z tych 2 metod

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

in viewWillDisappear miganie nadal występuje, ale tylko wtedy, gdy obraz cienia pojawia się ponownie, a nie sam pasek nawigacji.

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
źródło
1

dla swift3 należy napisać nieco inaczej:

 self.navigationController?.navigationBar.setBackgroundImage(UIImage(),
    for: UIBarMetrics.default)
   self.navigationController?.navigationBar.shadowImage = UIImage()
Chetan Dobariya
źródło
1

To jest uproszczona wersja odpowiedzi Gaurava Chandarany .

extension UINavigationBar {

    func hideShadow(_ value: Bool = true) {
        setValue(value, forKey: "hidesShadow")
    }
}
Scott Gardner
źródło
1

Delegat aplikacji

UINavigationBar.appearance().setBackgroundImage(UIImage(), for: UIBarMetrics.default)
UINavigationBar.appearance().shadowImage = UIImage()
CSE 1994
źródło
1

Jeśli chcesz usunąć tylko dolną linię i zachować jednolity kolor NavigationBar, dodaj te wiersze kodu w viewDidLoad: Swift 3, 4:

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

Pokój!

Mihail Salari
źródło
0

Linia graniczna to UIImageView, a usunięcie widoku podrzędnego, który jest obrazem, spowoduje usunięcie barButtonItems z UIImageView. Poniższy kod pomoże Ci go usunąć. Mam nadzieję, że pomoże to komuś, kto stanął przed problemem takim jak ja.

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

Obramowanie UIImageView ma tylko 0,5 wysokości, więc ten kod usuwa tylko to.

Bachman
źródło
To spowodowało u mnie awarie. Myślę, że ParentViews i childViews muszą zostać rozpakowane na wypadek, gdyby były zerowe przed sprawdzeniem każdego z nich. Używam jednak niestandardowego UINavigationController, więc może to nie mieć miejsca w przypadku innych użytkowników ze standardowym paskiem.
Natalia,
0

W ramach AppDelegate globalnie zmieniło to format NavBar i usuwa dolną linię / obramowanie:

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

Nie udało mi się zaimplementować niczego innego na konkretnym VC, ale to pomoże 90% ludzi

David West
źródło
UINavigationBar.appearance (). BackgroundColor = UIColor.redColor () nie jest wymagana.
sabiland
0

to jest odpowiedź w szybkiej 3 bazie odpowiedzi Nate Cooka

   self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
    self.navigationController?.navigationBar.shadowImage = UIImage()
Alan
źródło
0

iOS 11 i Swift 4 Powinieneś spróbować podążać za nimi, jeśli chcesz usunąć obramowanie, ale nie chcesz, aby pasek nawigacyjny był półprzezroczysty
self.navigationBar.shadowImage = UIImage()

BilalReffas
źródło
0

w swoim niestandardowym kontrolerze nawigacji dodaj następujące wiersze:

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

Ważna uwaga

ostatnia linia jest ważna, jeśli używasz metody viewDidLoad () pierwszej linii, ponieważ navigationController powinien przerysować pasek nawigacyjny, ale łatwo możesz go użyć bez layoutIfNeeded () w metodzie viewWillAppear (), zanim narysuje pasek nawigacji

Panie Zee
źródło
0

Szybsza metoda Jacka Chena:

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

Za pomocą:

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

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        navigationController?.isHiddenHairline = false
    }
Mickael Belhassen
źródło
0
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithTransparentBackground()
GIJoeCodes
źródło