Как убрать нижнюю линию (1px) у UINavigationBar в iOS
Проблема с нижней линией 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 локально, глобальная настройка не применится. В таких случаях используйте первый ответ с вызовом в конкретном контроллере.
Ответов пока нет.
Войдите чтобы оставить ответ