IOS: стиль строки состояния по умолчанию с UIViewControllerBasedStatusBarAppearance ДА

Есть ли способ установить стиль строки состояния по умолчанию при сохранении UIViewControllerBasedStatusBarAppearance?

Вот проблема, с которой я имею дело:

Почти все приложение должно использовать UIStatusBarStyle.LightContent, поскольку панель навигации имеет темный фон. Первоначально UIViewControllerBasedStatusBarAppearance был отключен, и в строке Info.plist было установлено следующее: в строке состояния статуса текста:

<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>

Это работало очень хорошо, пока я не узнал, что эта строка состояния .LightContent показана даже для некоторых расширений общего доступа, таких как Facebook Messenger, что делает ее нечитаемой:

Стиль отображения состояния подсветки в Facebook Messenger

Это можно решить, используя UIViewControllerBasedStatusBarAppearance, но тогда мне нужно будет добавить следующий метод ко всем контроллерам представлений, которые я хочу избежать, поскольку приложение достаточно велико.

Кроме того, для одного экрана приложения, имеющего светлый навигационный фон, я переключился на темную навигационную панель с помощью UIApplication.sharedApplication().setStatusBarStyle(), но этот метод устарел в iOS 9.

Есть идеи, как это решить? Swizzling?

Ответ 1

Решение

Самый простой и самый чистый способ добиться этого - добавить следующую строку в метод AppDelegate application:willFinishLaunchingWithOptions:

UINavigationBar.appearance().barStyle = .Black

Это приведет к тому, что .LightContent будет использоваться в качестве стиля строки состояния по умолчанию для приложения, пока ваше приложение использует UINavigationController.

Не забудьте сохранить следующий параметр в приложении Info.plist, если вы хотите использовать стиль строки .LightContent в строке состояния во время запуска для экрана заставки:

<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>

TL; DR

Моя текущая настройка, которая очень похожа на многие другие приложения, использует UITabBarController как самый верхний контроллер с стеком UINavigationController для каждой вкладки.

UINavigationController заботится о стиле строки состояния (как следует) и не вызывать preferredStatusBarStyle() на своих дочерних контроллерах. Таким образом, реализация подклассического решения, предложенного параметром, не работает в моем случае.

Дальнейшее подклассирование пользовательского подкласса UINavigationController Я использую не будет также чистым решением.

Теперь, когда приложение UIViewControllerBasedStatusBarAppearance включено и исправлено стиль строки состояния повсюду в самом приложении, SFSafariViewController и расширение общего доступа, такое как Messages, Mail и т.д., также используйте правильный стиль строки состояния (.Default).

Единственное исключение, в котором не используется правильный стиль строки состояния, - это расширение Facebook Messenger, упомянутое в вопросе. Однако, похоже, это ошибка в самом расширении, поскольку все приложения, которые я пробовал, использующие стиль строки .LightContent (например, Twitter), имеют такую ​​же проблему - представленное расширение FB Messenger из приложения имеет строку состояния с текстом белого цвета.

Ответ 2

Решение, которое я использую довольно часто, - это создать класс контроллера базового представления, из которого все контроллеры представлений в моем приложении. Это имеет то преимущество, что позволяет использовать функциональные возможности стиля строки состояния на основе View-Control со стандартным (светлым или темным) стилем, который затем может быть переопределен на основе каждого контроллера при необходимости.

Контроллер базового представления также очень удобен, когда вы начинаете получать изменения на основе набора признаков, настраиваемые анимации перехода, которые вы хотите использовать для большинства контроллеров просмотра, центральную точку для отслеживания аналитики и другие полезные вещи.

Да, вам нужно пройти через потенциально большую исходную базу и изменить все свои UIViewController на BaseViewController s, но это часто так же просто, как глобальный поиск и замена.

Вот что выглядит BaseViewController со способами, связанными со статусом:

class BaseViewController: UIViewController {
    var statusBarHidden: Bool = false { didSet { setNeedsStatusBarAppearanceUpdate() } }
    var statusBarStyle: UIStatusBarStyle = .lightContent { didSet { setNeedsStatusBarAppearanceUpdate() } }
    var statusBarUpdateAnimation: UIStatusBarAnimation = .fade { didSet { setNeedsStatusBarAppearanceUpdate() } }

    override var preferredStatusBarStyle: UIStatusBarStyle { return statusBarStyle }
    override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation { return statusBarUpdateAnimation }
    override var prefersStatusBarHidden: Bool { return statusBarHidden }
}

Для всех контроллеров, использующих стиль по умолчанию, вам не нужно ничего особенного:

class ViewController: BaseViewController { }

В тех случаях, когда вам нужна черная строка состояния, выполните:

class DarkStatusBarViewController: BaseViewController {
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        statusBarStyle = .default
    }
}

Обратите внимание, что вы можете переименовать DarkStatusBarViewController выше в DarkStatusBarBaseViewController и извлечь из него вместо BaseViewController, когда вам нужна темная строка состояния. Затем вам не нужно дублировать код состояния в каждом контроллере представления, который ему нужен, и вы поддерживаете приятную линейную связь для всех ваших BaseViewController функциональных возможностей.