Введение: почему скрытие Navigation Bar — это боль для новичка?
Вы когда-нибудь сталкивались с ситуацией: создаёте приложение, первый экран должен выглядеть как полноэкранный лендинг, без серой полоски сверху, а на втором экране Navigation Bar уже нужен для навигации? Казалось бы, логично просто написать navigationController?.isNavigationBarHidden = true во viewDidLoad. Но тут начинается магия: Navigation Bar может «вылезти» обратно при возврате с другого экрана, анимация ломается, или он вообще не скрывается.
Это один из самых популярных вопросов на Stack Overflow (тема «How to hide a navigation bar from first ViewController in Swift?» набрала тысячи просмотров). В этом туториале мы разберём не только базовое решение, но и тонкие моменты: как сделать это красиво, без багов с анимацией, и как адаптировать под современные iOS-стандарты. Если вы ищете надёжный способ скрыть navigation bar на первом экране в Swift — вы по адресу.
Проблема: что происходит «под капотом»?
Когда вы используете UINavigationController, он управляет Navigation Bar для всех дочерних контроллеров. Если вы просто скрываете его в viewDidLoad первого ViewController, при переходе на второй экран и возврате назад свойство может сброситься. Почему?
- viewDidLoad вызывается один раз — при повторном показе экрана код не выполнится.
- UINavigationController синхронизирует bar на основе последнего контроллера в стеке.
- Анимация перехода может «зажевать» состояние, если не задать
animatedпараметры.
Но не переживайте — решение элегантное и простое. Давайте напишем код.
Базовое решение: скрываем Navigation Bar в первом ViewController
Самый прямой способ — переопределить метод viewWillAppear. Почему именно здесь? Потому что этот метод вызывается каждый раз перед появлением экрана, в отличие от viewDidLoad. Таким образом, даже после возврата с другого экрана Navigation Bar снова скроется.
Шаг 1: Создаём первый ViewController
Допустим, у вас есть FirstViewController, который является корневым в UINavigationController.
import UIKit
class FirstViewController: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Скрываем Navigation Bar без анимации
navigationController?.setNavigationBarHidden(true, animated: animated)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Возвращаем Navigation Bar при уходе с экрана
navigationController?.setNavigationBarHidden(false, animated: animated)
}
}
Обратите внимание: мы используем setNavigationBarHidden(_:animated:) с параметром animated. Если передать true, Navigation Bar будет скрываться/появляться с анимацией, синхронизированной с переходом. Это выглядит профессионально.
Шаг 2: Настраиваем второй экран
На втором экране (SecondViewController) Navigation Bar будет отображаться по умолчанию. Ничего дополнительно писать не нужно — он появится автоматически при переходе.
Шаг 3: Проверяем в Interface Builder или коде
Убедитесь, что ваш UINavigationController настроен правильно. Если вы используете Storyboard, проверьте, что первый экран — это FirstViewController. Если в коде:
let navController = UINavigationController(rootViewController: FirstViewController())
Готово! Запустите приложение — первый экран будет без Navigation Bar, второй — с ним.
Продвинутые техники: анимация и SwiftUI
Базовое решение работает, но в реальных проектах часто нужны нюансы. Рассмотрим несколько сценариев.
Сценарий 1: Плавное скрытие с анимацией
Если вы хотите, чтобы Navigation Bar исчезал плавно при скролле или по тапу, можно использовать UIView.animate:
func hideNavigationBarAnimated() {
UIView.animate(withDuration: 0.3) {
self.navigationController?.navigationBar.alpha = 0
}
navigationController?.navigationBar.isHidden = true // На всякий случай
}
Но будьте осторожны: изменение alpha может привести к артефактам. Лучше использовать встроенный метод setNavigationBarHidden с анимацией.
Сценарий 2: Использование UINavigationControllerDelegate
Если у вас сложная иерархия и вы хотите управлять видимостью Navigation Bar централизованно, реализуйте протокол UINavigationControllerDelegate:
class CustomNavigationController: UINavigationController, UINavigationControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
}
func navigationController(_ navigationController: UINavigationController,
willShow viewController: UIViewController,
animated: Bool) {
// Скрываем Navigation Bar только для первого экрана
let hideBar = viewController is FirstViewController
navigationController.setNavigationBarHidden(hideBar, animated: animated)
}
}
Этот подход особенно полезен, если у вас много экранов и вы не хотите писать код в каждом контроллере.
Сценарий 3: SwiftUI и NavigationView
Если вы пишете на SwiftUI, задача решается ещё проще. Используйте модификатор .navigationBarHidden:
struct FirstView: View {
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: SecondView()) {
Text("Перейти")
}
}
.navigationBarHidden(true)
}
}
}
struct SecondView: View {
var body: some View {
Text("Второй экран")
.navigationBarHidden(false) // Показываем Navigation Bar
}
}
В SwiftUI Navigation Bar автоматически управляется через модификаторы, но будьте внимательны: если вы используете .navigationBarHidden(true) на первом экране, на втором нужно явно указать false, иначе бар может не появиться.
Частые ошибки и как их избежать
Даже опытные разработчики иногда наступают на эти грабли. Вот топ-3 ошибки при попытке скрыть navigation bar в Swift:
- Забыли про viewWillDisappear — если вы скрыли бар на первом экране, но не вернули его при уходе, второй экран тоже будет без бара. Всегда парно используйте
viewWillAppearиviewWillDisappear. - Использование isNavigationBarHidden = true без анимации — при переходе назад может возникнуть «моргание» бара. Всегда используйте
setNavigationBarHidden(_:animated:). - Попытка скрыть бар в viewDidLoad — это сработает только при первом появлении. При возврате с другого экрана бар появится снова.
Почему это важно для UX?
Скрытие Navigation Bar на первом экране