iOS:UIViewControllerBasedStatusBarAppearance为YES时的默认状态栏样式

11

在启用UIViewControllerBasedStatusBarAppearance的情况下如何设置默认状态栏样式?

这是我正在处理的问题:

几乎整个应用程序需要使用UIStatusBarStyle.LightContent作为导航栏具有深色背景。最初,UIViewControllerBasedStatusBarAppearance被禁用,以下内容在Info.plist中设置为白色文本状态栏:

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

这一切都很顺利,直到我发现即使在Facebook Messenger等一些共享扩展中也显示了.LightContent状态栏,导致其不可读:

Facebook Messenger Share Extension light status bar style

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

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

有什么想法可以解决这个问题吗?使用Swizzling吗?


1
我使用了一个变通方法,并使用以下代码行来更新状态栏颜色:self.navigationController?.navigationBar.barStyle = UIBarStyle.black,如果您想将其设置为 UIBarStyle.default - MSU_Bulldog
一个可能的 hacky 解决方法(未经测试)是,不是将该方法添加到所有视图控制器中,而是编写 ViewController 类的扩展,其中包含该方法。 - nbloqs
2个回答

7

解决方案

最简单、最干净的方法是在 AppDelegateapplication:willFinishLaunchingWithOptions 方法中添加以下行:

UINavigationBar.appearance().barStyle = .Black

这将使得.LightContent成为应用程序中的默认状态栏样式,只要您的应用程序使用UINavigationController即可。
如果想在启动时使用.LightContent状态栏样式来显示闪屏,请不要忘记在应用程序的Info.plist中保留以下设置:
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>

简述

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

UINavigationController负责状态栏样式(正如它应该的那样),并且不会在其子视图控制器上调用preferredStatusBarStyle()。因此,在我的情况下,实现par提出的子类化解决方案无效。

进一步子类化我正在使用的UINavigationController的自定义子类也不是一个干净的解决方案。

现在,由于应用本身启用了UIViewControllerBasedStatusBarAppearance并且正确地在整个应用程序中使用状态栏样式,像SFSafariViewController和共享扩展(例如Messages、Mail等)也使用了正确的(.Default)状态栏样式。

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


3
我经常使用的解决方案是创建一个基本视图控制器类,所有应用程序中的视图控制器都从该类派生出来。这样做的好处是可以使用基于视图控制器的状态栏样式设置功能,并具有默认的(浅色或深色)样式,可以根据需要在每个视图控制器上进行覆盖。
一旦你开始了解trait-collection变化、自定义转换动画和其他有用的事情,基础视图控制器也非常方便。
是的,你必须浏览所有的可能大量的源代码并将所有的UIViewController更改为BaseViewController,但这通常只需要全局搜索和替换即可。
以下是与状态栏相关的方法的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功能维护良好的线性关系。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接