Avatar ·

Как убрать нижнюю линию (1px) у UINavigationBar в iOS

Всем привет! Я начинающий iOS-разработчик, и у меня возникла проблема с дизайном навигационной панели. Я хочу сделать UINavigationBar полностью прозрачным, без стандартной серой линии внизу (эту линию часто называют "1px bottom line" или shadow image). Я перепробовал несколько способов, но ничего не работает. Вот мой текущий код на Swift, где я пытаюсь убрать эту линию: ```swift override func viewDidLoad() { super.viewDidLoad() navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default) navigationController?.navigationBar.shadowImage = UIImage() navigationController?.navigationBar.isTranslucent = true } ``` Но линия всё равно остаётся! Я также пробовал устанавливать `shadowImage` в nil, но это тоже не помогло. Ещё я заметил, что если я ставлю `isTranslucent = false`, то фон панели становится белым, и линия всё равно видна. Подскажите, пожалуйста, как правильно убрать эту нижнюю границу? Может быть, есть какой-то другой способ, который работает во всех версиях iOS (от iOS 13 и выше)? Буду благодарен за любые советы и примеры кода! <<>>

Проблема с нижней линией UINavigationBar

Стандартная линия внизу UINavigationBar — это shadowImage, который по умолчанию рисуется системой. Ваш код близок к правильному, но есть нюансы, связанные с тем, как UIKit обрабатывает прозрачные изображения и настройки внешнего вида.

Основное решение (iOS 13+ и более старые версии)

Лучший способ — использовать современный API через UINavigationBarAppearance, который появился в iOS 13. Этот подход гарантированно работает и для новых, и для старых версий, если вы добавите fallback.

// Swift 5, iOS 13+
extension UINavigationBar {
    func removeBottomLine() {
        if #available(iOS 13.0, *) {
            let appearance = UINavigationBarAppearance()
            appearance.configureWithTransparentBackground()
            appearance.shadowImage = UIImage() // Убираем тень/линию
            appearance.shadowColor = .clear    // Дополнительная гарантия
            
            self.standardAppearance = appearance
            self.compactAppearance = appearance
            self.scrollEdgeAppearance = appearance
        } else {
            // Fallback для iOS 12 и ниже
            self.setBackgroundImage(UIImage(), for: .default)
            self.shadowImage = UIImage()
            self.isTranslucent = true
        }
    }
}

// Использование в контроллере
override func viewDidLoad() {
    super.viewDidLoad()
    navigationController?.navigationBar.removeBottomLine()
}

Почему это работает?

  • configureWithTransparentBackground() — делает фон полностью прозрачным, убирая стандартный цвет.
  • shadowImage = UIImage() — заменяет тень на пустое изображение (пустой UIImage — это прозрачная картинка размером 0x0).
  • shadowColor = .clear — дополнительно убирает цвет тени (нужно для iOS 15+, где Apple изменила поведение).
  • Назначение на standardAppearance, compactAppearance и scrollEdgeAppearance — гарантирует, что линия исчезнет во всех состояниях (обычный, компактный, скролл).

Важные замечания

  • Не забудьте про прозрачность фона. Если вы хотите, чтобы панель была непрозрачной, но без линии, используйте appearance.configureWithOpaqueBackground() и задайте нужный цвет через appearance.backgroundColor. Линия всё равно исчезнет.
  • Проверьте на iOS 15+. Начиная с iOS 15, UINavigationBar может показывать линию при скролле, если не настроен scrollEdgeAppearance. Наш код это учитывает.
  • Если линия всё ещё видна — возможно, вы вызываете код до того, как панель добавлена на экран. Перенесите вызов в viewWillAppear(_:) или используйте DispatchQueue.main.async.

Альтернативный способ для iOS 13+ (без расширения)

if #available(iOS 13.0, *) {
    let appearance = UINavigationBarAppearance()
    appearance.configureWithTransparentBackground()
    appearance.shadowImage = UIImage()
    appearance.shadowColor = .clear
    navigationController?.navigationBar.standardAppearance = appearance
    navigationController?.navigationBar.compactAppearance = appearance
    navigationController?.navigationBar.scrollEdgeAppearance = appearance
} else {
    navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
    navigationController?.navigationBar.shadowImage = UIImage()
    navigationController?.navigationBar.isTranslucent = true
}

Этот код можно вставить прямо в viewDidLoad() вашего контроллера. Он полностью решает проблему и убирает нижнюю линию на всех устройствах и версиях iOS.

<<>>

Быстрый хак через appearance (если не хотите менять код каждого контроллера)

Если вам нужно убрать линию глобально для всех навигационных панелей в приложении, используйте UINavigationBar.appearance(). Это особенно удобно, если у вас много экранов.

// В AppDelegate или сцене (application(_:didFinishLaunchingWithOptions:))
if #available(iOS 13.0, *) {
    let appearance = UINavigationBarAppearance()
    appearance.configureWithTransparentBackground()
    appearance.shadowImage = UIImage()
    appearance.shadowColor = .clear
    UINavigationBar.appearance().standardAppearance = appearance
    UINavigationBar.appearance().compactAppearance = appearance
    UINavigationBar.appearance().scrollEdgeAppearance = appearance
} else {
    UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)
    UINavigationBar.appearance().shadowImage = UIImage()
    UINavigationBar.appearance().isTranslucent = true
}

Важный нюанс

Если вы используете UINavigationController с prefersLargeTitles = true, убедитесь, что вы также настроили compactAppearance — иначе при переходе от большого заголовка к маленькому линия может появиться снова. Наш код это уже учитывает.

Этот подход сработает мгновенно для всех экранов, но помните: если какой-то контроллер переопределяет standardAppearance локально, глобальная настройка не применится. В таких случаях используйте первый ответ с вызовом в конкретном контроллере.