Как быстро удалить границу навигационной панели?

131

Я безуспешно пытался удалить границу навигационных панелей. Я исследовал, и люди, кажется, говорят, что для shadowImage и BackgroundImage нужно значение nil, но в моем случае это не работает.

Мой код

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

иллюстрации:

введите описание изображения здесь

Питер Пик
источник

Ответы:

309

Проблема в этих двух строках:

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

Поскольку у вас нет изображения без имени, UIImage(named: "")возвращается nil, что означает, что срабатывает поведение по умолчанию:

Если не равно нулю, пользовательское теневое изображение будет отображаться вместо теневого изображения по умолчанию. Чтобы пользовательская тень отображалась, пользовательское фоновое изображение также должно быть установлено с помощью -setBackgroundImage: forBarMetrics: (если используется фоновое изображение по умолчанию, будет использоваться изображение тени по умолчанию).

Вам нужен действительно пустой образ, поэтому просто инициализируйте его UIImage():

self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
self.navigationController?.navigationBar.shadowImage = UIImage()
Нейт Кук
источник
2
Этот ответ действительно работает. Потому что, если использовать принятый ответ (код), его удалить из панели инструментов imageViews в.
Сергей Красюк
1
Это должен быть принятый ответ. Также работает при настройке из UINavigationBar.appearance ()
Хайнриш
1
Это должен быть принятый ответ для Swift 3. Принятый ответ работал у меня в Swift 2, но не в Swift 3
ColinMasters
1
для swift3 вы должны написать немного иначе: self.navigationController? .navigationBar.setBackgroundImage (UIImage (), для: UIBarMetrics.default) self.navigationController? .navigationBar.shadowImage = UIImage ()
Chetan Dobariya
5
Этот метод конфликтует с большим заголовком в iOS 11
SteffenK
53

Swift 4 и Swift 5

Удаление границы:

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

Восстановление границы:

self.navigationController?.navigationBar.setBackgroundImage(nil, for:.default)
self.navigationController?.navigationBar.shadowImage = nil
self.navigationController?.navigationBar.layoutIfNeeded()
Сазад Хисейн Хан
источник
2
Идеальный ответ :)
PJR
Нужен ли нам здесь layoutIfNeeded ()?
korgx9
1
Да korgx9, он нам нужен. В противном случае он не изменит цвет до следующего розыгрыша.
Sazzad Hissain Khan
37

это полностью удалит теневое изображение

for parent in self.navigationController!.navigationBar.subviews {
 for childView in parent.subviews {
     if(childView is UIImageView) {
         childView.removeFromSuperview()
     }
 }
}
Стив Пэйн
источник
1
Не могли бы вы уточнить?
Kmeixner
1
Также для меня работает это решение, а ответ @Nate Cook не работает. : S
Лука Даванцо
2
Святая ограда !! После всех поисков это ЕДИНСТВЕННОЕ, что сработало.
Туан Ань Ву
он работает, но также у меня есть значок меню на панели навигации, и он исчез: / я просто хочу, чтобы граница была стерта. HELP: /
Стефи Саманьего
Это сработало для меня, но после нажатия нового ViewController он удаляет оттуда строку. Как я могу этого избежать?
Anirudha Mahale
36

В Swift 2 это можно сделать следующим образом:

Файл AppDelegate

Внутри приложения func (..., didFinishLaunchingWithOptions launchOptions: ...)

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

для Swift 3:

UINavigationBar.appearance().shadowImage = UIImage()
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)
Хорхе Касариего
источник
Правильный ответ.
Ред.
Это исчерпывающий ответ!
madeny
Лучше написать такие полезные значения по умолчанию в Appdelegate, чем писать их в нечетных местах. Правильный ответ :)
Md Rais
35

Просто напишите это в расширении UINavigationBar

extension UINavigationBar {

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

И в вашем viewController ...

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

И чтобы отменить это для любого viewController, просто передайте false.

Гаурав Чандарана
источник
Это отлично работает, НО это скрывает, если для ВСЕХ vcs в стеке навигации. Если вы используете его в vc1, а vc1 может нажимать на vc2, он также будет скрыт на vc2. Чтобы показать тень в vc2, вам нужно будет установить для нее значение false в viewDidLoad. Проблема в том, что когда вы вернетесь к vc1, он снова появится, потому что он был сброшен в vc2. Вы должны использовать логику, чтобы двигаться вперед и назад, что, возможно, того не стоит. Однако, если вы вообще не хотите, чтобы теневое изображение отображалось на каких-либо виртуальных компьютерах, это самый простой способ
Лэнс Самария
Допустим, у нас есть стек viewControllers с 5 viewController (и мы скрыли тень в первом). Теперь только для 3-го viewController, я НЕ хочу скрывать тень. Итак, я вызову этот метод с FALSE в viewWillAppear и с TRUE в viewWillDisappear 3-го viewController. Это все, что нужно!
Gaurav Chandarana,
Ваше абсолютно правильное, хорошее мышление! Не думайте, что я выбил ваш ответ, потому что он очень сжатый и эффективный, я тоже проголосовал за него. Я использую его, чтобы удалить его и панель навигации для сообщений об ошибках. Проблема, которую я обнаружил, заключалась в том, чтобы удалить его в vc1, но показать его vc2, но если произошла ошибка в vc2, удаление его в viewWillDisappear может не сработать. Но опять же, это уникальная ситуация. Мне нравится идея viewWillDisappear для общего использования, и вы должны добавить ее в свой ответ. Независимо от того, что ваш код работает, и это простой способ удалить тень! 👍🏿👍🏿
Лэнс Самария
Работает как шарм. Просто хотите убедиться, что это не личные настройки?
inokey
2
Это отличный ответ! Я добавил ответ, который упрощает код.
Скотт Гарднер
13

Установите barStyleна .Blackперед установкой оттенка:

self.navigationController?.navigationBar.translucent = false
self.navigationController?.navigationBar.barStyle = .Black
self.navigationController?.navigationBar.barTintColor = UIColor.blueColor()
gpbl
источник
Случайно ли это, что это действительно работает? или я слишком много думаю?
joe
@joe ну тут работает :-) у тебя не работает?
gpbl
вот в чем дело, он ДЕЙСТВИТЕЛЬНО работает. Мне просто интересно, есть ли объяснение, почему при превращении barStyle в черный он затем превращает весь barTintColor в синий :)
Джо
возможно, установив его на черный и непрозрачный, он отключает некоторые слои / вид на
панели
Я попытался использовать это, и он удаляет нижнюю строку, однако, если использовать полосу белого оттенка, заголовок не виден: /
RileyDev
11

Swift 5

При использовании setBackgroundImage / shadowImage, чтобы скрыть линию роста волос, есть небольшая задержка. Этот метод убирает задержку. Кредит для Chameleon Framework . Это метод, который они используют (в 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
    }
}
Джек Чен
источник
1
FWIW, это единственное решение, которое сработало для меня на iOS 13.4 ...
Кевинстюбер,
9

Ответ Луки Даванцо отличный, но он не работает в iOS 10. Я изменил его, чтобы он работал в iOS 10 и ниже.

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

Вы также можете расширить UINavigationController и отключить его от этого. removeFromSuperview()on the line не будет работать на iOS 10, поэтому я просто установил альфа в 0, чтобы этот вызов был совместим везде.

Дэвид Баэз
источник
Хорошая уловка, есть ли способ показать / скрыть тень в некоторых viewControllers во время навигации?
Ashkan.H
Вам лучше проверить высоту, на которой есть height >= 1.0. На моделях iPhone с 3-кратным увеличением сетчатки (например, 8 Plus, XR ...) линия роста волос имеет высоту 0,33.
fl034
7

Чтобы удалить границу из UINavigationBar в Swift 3+, используйте:

UINavigationBar.appearance().shadowImage = UIImage()
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)
UINavigationBar.appearance().isTranslucent = false
reza_khalafi
источник
5

для Swift 3

в viewDidLoadметоде

navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
navigationController?.navigationBar.shadowImage = UIImage()
Gulz
источник
4

Только это сработало для меня,

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

ссылка

Мохаммад Заид Патан
источник
4

Обновлено для Swift 4 на случай, если кому-то интересно

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

Теперь это еще менее многословно.

Маурисио Чирино
источник
2

Вот как это сделать, если вы хотите сделать это без изменения цвета фона:

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

ПРИМЕЧАНИЕ. Это может привести к сбою в производственном приложении. По-видимому, NavigationBar не любит, когда его вид исчезает

Ярив Нисим
источник
2

Принятый ответ сработал для меня, но я заметил, что когда я хотел, чтобы теневое изображение снова появлялось при переходе назад или переходе к другому виртуальному компьютеру, на панели навигации было заметное мигание.

Используя этот метод navigationController?.navigationBar.setValue(true, forKey: "hidesShadow") в viewWillAppear, полоса тени скрыта в текущем контроллере видимого представления.

Используя эти 2 метода

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

в viewWillDisappear мигание все еще происходит, но только тогда, когда снова появляется теневое изображение, а не сама панель навигации.

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()
}
Копье Самария
источник
1

для swift3 вы должны написать немного иначе:

 self.navigationController?.navigationBar.setBackgroundImage(UIImage(),
    for: UIBarMetrics.default)
   self.navigationController?.navigationBar.shadowImage = UIImage()
Четан Добария
источник
1

Представитель приложения

UINavigationBar.appearance().setBackgroundImage(UIImage(), for: UIBarMetrics.default)
UINavigationBar.appearance().shadowImage = UIImage()
CSE 1994
источник
1

Если вы хотите удалить только нижнюю строку и сохранить сплошной цвет панели навигации, добавьте эти строки кода в viewDidLoad: Swift 3, 4:

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

Мир!

Михаил Салари
источник
0

Линия границы - это UIImageView, и при удалении подпредставления, которое является imageView, удаляются элементы barButtonItem с UIImageView. Код ниже поможет вам удалить его. Надеюсь, это поможет кому-то, кто сталкивался с такой проблемой, как я.

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

Граница UIImageView имеет высоту всего 0,5, поэтому этот код удаляет только ее.

Бахман
источник
Это вызвало у меня сбои. Я думаю, что parent и childViews необходимо развернуть на случай, если они равны нулю, прежде чем проверять каждый из них. Однако я использую собственный UINavigationController, поэтому это может быть не так для других пользователей со стандартной панелью.
Наталья
0

В AppDelegate это глобально изменило формат NavBar и удалило нижнюю строку / границу:

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

Не удалось реализовать что-то другое на конкретном венчурном капитале, но это поможет 90% людей

Дэвид Уэст
источник
UINavigationBar.appearance (). BackgroundColor = UIColor.redColor () не требуется.
sabiland
0

это ответ в быстрой базе 3 ответа Нейта Кука

   self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
    self.navigationController?.navigationBar.shadowImage = UIImage()
Алан
источник
0

iOS 11 и Swift 4 Если вы хотите удалить границу, но не делать полупрозрачной навигационной панели, попробуйте выполнить следующие действия.
self.navigationBar.shadowImage = UIImage()

BilalReffas
источник
0

в вашем настраиваемом navigationController добавьте эти строки:

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

Важная заметка

последняя строка важна, если вы используете метод viewDidLoad () первой строки, потому что navigationController должен перерисовывать панель навигации, но вы можете легко использовать это без layoutIfNeeded () в методе viewWillAppear () до того, как он отобразит панель навигации

Г-н Зи
источник
0

Более быстрый метод Джека Чена:

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

С помощью:

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

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        navigationController?.isHiddenHairline = false
    }
Микаэль Белхассен
источник
0
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithTransparentBackground()
GIJoeCodes
источник