Изменение цвета статус-бара для отдельных ViewControllers в iOS 8 на Swift
Правильное решение для iOS 8 и выше
Проблема в том, что вы не учли два ключевых момента: настройку Info.plist и особенности работы с UINavigationController. Давайте разберём всё по шагам.
Шаг 1: Настройка Info.plist
Добавьте в файл Info.plist ключ UIViewControllerBasedStatusBarAppearance (на русском: «Основанный на UIViewController внешний вид строки состояния») и установите его значение в YES (или true для Xcode). Это даст каждому ViewController возможность самостоятельно управлять цветом статус-бара. Если этот ключ отсутствует или установлен в NO, система будет использовать глобальную настройку из UIApplication.shared.statusBarStyle.
Шаг 2: Переопределение preferredStatusBarStyle
В вашем ViewController переопределите свойство preferredStatusBarStyle:
class MyViewController: UIViewController {
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent // Белый текст для тёмного фона
// Для чёрного текста используйте .default
}
}
Шаг 3: Обновление статус-бара после изменений
Если вы хотите динамически менять цвет (например, после смены темы), вызовите setNeedsStatusBarAppearanceUpdate():
class MyViewController: UIViewController {
var isDarkBackground = true
override var preferredStatusBarStyle: UIStatusBarStyle {
return isDarkBackground ? .lightContent : .default
}
func toggleBackground() {
isDarkBackground.toggle()
setNeedsStatusBarAppearanceUpdate() // Перерисовывает статус-бар
}
}
Шаг 4: Особенности с UINavigationController
Если ваш ViewController находится внутри UINavigationController, то именно NavigationController управляет статус-баром, а не ваш контроллер. Есть два решения:
- Вариант A (рекомендуемый): Создайте подкласс
UINavigationControllerи переопределите в нёмpreferredStatusBarStyle, делегируя выбор текущему контроллеру:
class CustomNavigationController: UINavigationController {
override var preferredStatusBarStyle: UIStatusBarStyle {
return topViewController?.preferredStatusBarStyle ?? .default
}
}
Используйте этот класс вместо стандартного UINavigationController в Storyboard или коде.
- Вариант B: В каждом дочернем контроллере переопределите
childForStatusBarStyle, возвращаяself. Но это сложнее и реже используется.
Полный пример для iOS 8
// В Info.plist: UIViewControllerBasedStatusBarAppearance = YES
class CustomNavigationController: UINavigationController {
override var preferredStatusBarStyle: UIStatusBarStyle {
return topViewController?.preferredStatusBarStyle ?? .default
}
}
class LightViewController: UIViewController {
override var preferredStatusBarStyle: UIStatusBarStyle {
return .default // Чёрный текст на белом фоне
}
}
class DarkViewController: UIViewController {
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent // Белый текст на тёмном фоне
}
}
Важное замечание для iOS 8
Метод UIApplication.shared.statusBarStyle действительно устарел в iOS 9, но в iOS 8 он ещё работал. Однако описанный выше подход с preferredStatusBarStyle полностью совместим с iOS 8 и является правильным способом. Убедитесь, что ваш проект настроен на iOS 8.0 как минимальную версию в настройках проекта (Deployment Target).
Альтернативный подход: Использование childForStatusBarStyle
Если вы не хотите создавать подкласс UINavigationController, можно переопределить свойство childForStatusBarStyle в вашем NavigationController. Это более гибкий способ, когда контроллер сам решает, кто будет управлять статус-баром.
class MyNavigationController: UINavigationController {
override var childForStatusBarStyle: UIViewController? {
return topViewController
}
}
Теперь каждый дочерний ViewController может переопределять preferredStatusBarStyle, и NavigationController будет делегировать управление ему. Этот подход работает начиная с iOS 7 и не требует дополнительных настроек в Info.plist (хотя ключ UIViewControllerBasedStatusBarAppearance всё равно рекомендуется установить в YES для совместимости).
Динамическое изменение без переопределения
Если вам нужно менять цвет статус-бара в зависимости от действий пользователя (например, при появлении модального окна), используйте setNeedsStatusBarAppearanceUpdate() в нужный момент. Это вызовет повторный запрос preferredStatusBarStyle у текущего контроллера.
class MyViewController: UIViewController {
@IBAction func buttonTapped(_ sender: UIButton) {
// Изменяем какое-то условие
setNeedsStatusBarAppearanceUpdate()
}
}
Обратите внимание: если у вас вложенные контроллеры (например, TabBarController внутри NavigationController), придётся переопределять childForStatusBarStyle на каждом уровне, чтобы цепочка делегирования работала корректно.