Avatar ·

Как изменить цвет панели навигации (UINavigationBar) в Swift?

Всем привет! Я новичок в iOS-разработке на Swift, и у меня возникла проблема с кастомизацией UINavigationBar. Я хочу изменить цвет фона панели навигации в моем приложении, но ничего не получается. У меня есть стандартный NavigationController, который я добавил через Storyboard. Я пробовал менять цвет в коде внутри viewDidLoad() своего первого ViewController, но цвет остается стандартным (белым/полупрозрачным). Вот что я пробовал: ```swift override func viewDidLoad() { super.viewDidLoad() navigationController?.navigationBar.barTintColor = UIColor.blue navigationController?.navigationBar.backgroundColor = UIColor.blue } ``` Я также пробовал установить цвет в AppDelegate, но безуспешно. В некоторых статьях пишут, что нужно использовать `isTranslucent = false`, а в других — что все изменилось в новых версиях iOS. Я использую Xcode 14 и iOS 16. Подскажите, пожалуйста, как правильно изменить цвет UINavigationBar во всем приложении? Мне нужно, чтобы панель была полностью синей, без прозрачности, и текст (заголовок) был белым. Буду благодарен за подробный пример кода! <<>>

Правильный способ изменения цвета UINavigationBar в Swift (iOS 13+)

Ваша проблема типична для начинающих разработчиков. Начиная с iOS 13, Apple изменила подход к кастомизации UINavigationBar. Старые свойства, такие как barTintColor и backgroundColor, больше не работают так, как раньше. Теперь используется UINavigationBarAppearance.

Решение для iOS 13 и новее

Лучший способ — настроить внешний вид через UINavigationBarAppearance и применить его глобально или к конкретному навигационному контроллеру. Вот полный пример:

// В AppDelegate.swift или в любом месте перед отображением навигации
func setupNavigationBarAppearance() {
    // Создаем объект appearance
    let appearance = UINavigationBarAppearance()
    
    // Настраиваем цвета
    appearance.configureWithOpaqueBackground() // Убирает прозрачность
    appearance.backgroundColor = UIColor.systemBlue // Цвет фона
    
    // Настраиваем цвет заголовка
    appearance.titleTextAttributes = [.foregroundColor: UIColor.white]
    appearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
    
    // Настраиваем цвет кнопок (back button, bar button items)
    let buttonAppearance = UIBarButtonItemAppearance()
    buttonAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.white]
    appearance.buttonAppearance = buttonAppearance
    
    // Настраиваем цвет стрелки "Назад"
    appearance.backButtonAppearance = buttonAppearance
    
    // Применяем глобально ко всем UINavigationBar
    UINavigationBar.appearance().standardAppearance = appearance
    UINavigationBar.appearance().compactAppearance = appearance
    UINavigationBar.appearance().scrollEdgeAppearance = appearance
}

Вызовите этот метод в application(_:didFinishLaunchingWithOptions:):

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    setupNavigationBarAppearance()
    return true
}

Если нужно изменить цвет только для одного экрана

Просто примените appearance к конкретному navigationController:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    
    let appearance = UINavigationBarAppearance()
    appearance.configureWithOpaqueBackground()
    appearance.backgroundColor = UIColor.systemGreen
    appearance.titleTextAttributes = [.foregroundColor: UIColor.white]
    
    navigationController?.navigationBar.standardAppearance = appearance
    navigationController?.navigationBar.compactAppearance = appearance
    navigationController?.navigationBar.scrollEdgeAppearance = appearance
}

Почему ваш старый код не работал?

  • barTintColor — устарел с iOS 13. Он игнорируется, если установлен scrollEdgeAppearance.
  • backgroundColor — работает только для фона, но не влияет на прозрачность.
  • isTranslucent — если установить false, панель станет непрозрачной, но цвет все равно нужно задавать через appearance.

Полный пример с восстановлением стандартного цвета

Если вы хотите вернуть стандартный цвет на других экранах, сохраните исходный appearance:

// Сохраняем дефолтный appearance
let defaultAppearance = UINavigationBar.appearance().standardAppearance

// На экране с кастомным цветом
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    let customAppearance = UINavigationBarAppearance()
    customAppearance.configureWithOpaqueBackground()
    customAppearance.backgroundColor = UIColor.orange
    navigationController?.navigationBar.standardAppearance = customAppearance
}

// При уходе с экрана
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    navigationController?.navigationBar.standardAppearance = defaultAppearance
}

Теперь ваша панель навигации будет синей с белым текстом на всех экранах. Не забудьте импортировать UIKit — это все, что нужно.

<<>>

Альтернативный подход: через Storyboard и User Defined Runtime Attributes

Если вы не хотите писать много кода, можно настроить цвет UINavigationBar прямо в Storyboard с помощью User Defined Runtime Attributes. Это особенно удобно для быстрого прототипирования.

Как сделать:

  1. Выберите ваш Navigation Controller в Storyboard.
  2. Перейдите на вкладку "Identity Inspector" (четвертая иконка справа).
  3. В разделе "User Defined Runtime Attributes" добавьте новые ключи:
Key Path: navigationBar.standardAppearance.backgroundColor
Type: Color
Value: выберите нужный цвет (например, System Blue)

Key Path: navigationBar.standardAppearance.titleTextAttributes
Type: Dictionary
Value: добавьте ключ NSForegroundColorAttributeName со значением White Color

Также добавьте для compactAppearance и scrollEdgeAppearance, если нужно.

Минусы этого подхода:

  • Сложно поддерживать при изменении дизайна.
  • Нельзя легко переиспользовать между разными проектами.
  • Нет проверки типов — легко ошибиться в названии ключа.

Поэтому для продакшена рекомендую использовать первый способ с кодом. А этот метод подойдет для быстрых экспериментов или если вы только учитесь.