iOS: 默认状态栏样式与 UIViewControllerBasedStatusBarAppearance YES

iOS: Default status bar style with UIViewControllerBasedStatusBarAppearance YES

有没有办法在保持 UIViewControllerBasedStatusBarAppearance 启用的同时设置默认状态栏样式?

这是我正在处理的问题:

几乎整个应用程序都需要使用 UIStatusBarStyle.LightContent,因为导航栏的背景是深色的。本来禁用了UIViewControllerBasedStatusBarAppearance,在Info.plist里面设置了while text status status bar:

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

这工作得很好,直到我发现这个 .LightContent 状态栏甚至对于某些共享扩展程序(如 Facebook Messenger)也会显示,导致它不可读:

这可以通过使用 UIViewControllerBasedStatusBarAppearance 来解决,但是我需要将以下方法添加到所有视图控制器中,因为应用程序非常大,所以我想避免这样做。

此外,对于应用程序中具有浅色导航栏背景的一个屏幕,我使用 UIApplication.sharedApplication().setStatusBarStyle() 切换到深色导航栏,但这种方法在 iOS 9 中已弃用。

有什么解决办法吗?摇摆不定?

我经常使用的一个解决方案是创建一个基本视图控制器class,我的应用程序中的所有视图控制器都来自该视图控制器。这样做的好处是允许使用具有默认(浅色或深色)样式的 view-controller-based 状态栏 style-setting 功能,然后可以根据需要在 per-view-controller 基础上覆盖它。

一旦您开始了解基于 trait-collection 的更改、大多数视图控制器所需的自定义过渡动画、分析跟踪的中心点和其他有用的东西,基本视图控制器也非常方便。

是的,您必须检查潜在的庞大源库并将所有 UIViewController 更改为 BaseViewController,但这通常与全局 search-and-replace 一样容易。

下面是 BaseViewController 和 status-bar 相关方法的样子:

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 功能保持良好的线性关系。

解决方案

实现这一点的最简单和最干净的方法是在 AppDelegateapplication:willFinishLaunchingWithOptions 方法中添加以下行:

UINavigationBar.appearance().barStyle = .Black

只要您的应用使用 UINavigationController.

,这将使 .LightContent 作为整个应用的默认状态栏样式

如果想在初始屏幕启动期间使用 .LightContent 状态栏样式,请不要忘记在应用的 Info.plist 中保留以下设置:

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

TL;DR

我当前的设置与许多其他应用程序非常相似,使用 UITabBarController 作为最顶层的控制器,每个选项卡都有 UINavigationController 个堆栈。

UINavigationController 负责状态栏样式(应该如此)并且不在其子视图控制器上调用 preferredStatusBarStyle()。因此,实施 对我来说不起作用。

进一步继承 UINavigationController I'm using 的自定义子类也不是一个干净的解决方案。

现在,由于该应用程序已 UIViewControllerBasedStatusBarAppearance 启用并在应用程序本身的任何地方纠正了状态栏样式,SFSafariViewController 和共享扩展程序(如消息、邮件等)使用正确的(.Default) 状态栏样式也是如此。

唯一没有使用正确状态栏样式的例外是问题中提到的 Facebook Messenger 的共享扩展。然而,这似乎是扩展本身的一个错误,因为我尝试过的所有使用 .LightContent 状态栏样式的应用程序(例如 Twitter)都有相同的问题 - 应用程序中显示的 FB Messenger 共享扩展程序有一个带有白色文本的状态栏。