如何在子视图控制器中更改iOS状态栏颜色

10

(iOS 7 Xcode 5.0.2)

我使用以下方法,在根视图控制器上成功将状态栏颜色更改为白色

[self setNeedsStatusBarAppearanceUpdate]; // Update status bar style

-(UIStatusBarStyle)preferredStatusBarStyle
{
    return UIStatusBarStyleLightContent; // Set status bar color to white
}

现在我正在尝试当切换到子视图控制器时将状态栏颜色更改为黑色,但我不知道如何做。(状态栏颜色仍然是白色)

我搜索了一下,并找到了这种方法:childViewControllerForStatusBarStyle。我阅读了苹果的文档,但仍然不知道如何/在哪里使用它,而且我不确定这是否是正确的方法。

是否有人知道如何在子视图控制器中更改状态栏颜色?


你的子视图控制器是否在导航控制器中? - James Frost
@JamesFrost 是的,是的。 - Strong84
6个回答

13

默认情况下,UINavigationController 似乎不提供一个合理的 childViewControllerForStatusBarStyle 实现。通过实现此方法,您可以告诉导航控制器将所有对 preferredStatusBarStyle 的调用推迟到其顶部的子视图控制器。

您可以通过创建子类 UINavigationController 并在其中实现该方法,或者简单地添加类别来实现。

@implementation UINavigationController (ChildStatusBarStyle)

- (UIViewController *)childViewControllerForStatusBarStyle 
{
    return self.topViewController;
}

@end

7
我不确定在子类中声明的方法(UINavigationController继承自UIViewController)提供一个类别是否是一个好主意——如果我没记错,这会导致未定义的行为,因为类别不是适当的重写。因此,我建议使用子类代替。尽管如此,这是个好答案! (+1) - Till
@JamesFrost 非常好的建议,我正在开始尝试如何使用它。让我试试然后过会儿再回复你。非常感谢! (+1) - Strong84
@Till 你好 Till,看一下上面的信息~ - Strong84
嗯... 我刚刚创建了一个只有一个视图控制器的新Xcode项目。我实现了 preferredStatusBarStyle 返回 UIStatusBarStyleLightContent,然后创建了一个包含上述方法的 UINavigationController 类别 - 它立刻生效了。 - James Frost
@JamesFrost 我知道出了什么问题:我忘记将我的视图控制器嵌入导航控制器中了... 非常感谢,你的答案很有效~ - Strong84
显示剩余2条评论

1

James Frost的答案是唯一一个对我有用的。谢谢!这是那段代码的Swift 4版本。

extension UINavigationController {
override open var childViewControllerForStatusBarStyle: UIViewController? {
    return topViewController
}
}

注意:这个目前有点笨重,建议添加一些代码将其范围限制在一个单独的视图控制器中。可以像这样实现:
extension UINavigationController {
override open var childViewControllerForStatusBarStyle: UIViewController? {
    if topViewController is MyViewController {
        return topViewController
    } else {
        return nil
    }
}
}

你显然需要用你自己的UIViewController子类替换MyViewController,并实现preferredStatusBarStyle方法。

override var preferredStatusBarStyle: UIStatusBarStyle {
    if isBackgroundDark() {
        return .lightContent
    } else {
        return .default
    }
}

再次强调,isBackgroundDark() 是你需要实现的。

最后不要忘记在你的 viewController 中每次 isBackgroundDark() 的值发生变化时调用 setNeedsStatusBarAppearanceUpdate()。


1
我刚刚发现: 当您正确地将根视图控制器嵌入 UINavigationController 时,您永远不需要创建类别来扩展导航控制器的功能,也不需要为相同目的子类化 UINavigationController。
您只需在每个视图控制器中放置 preferredStatusBarStyle,并记得调用 [self setNeedsStatusBarAppearanceUpdate]; 来更新状态栏样式。如此简单!
请查看来自 WWDC 2013 的此视频:点击这里

编辑:

我让它工作的原因是我偶然设置了UINavigationBar隐藏。在这种情况下,它的行为与根本不使用UINavigationController时相同。 当您尝试更改位于UINavigationController堆栈内的UIViewController的StatusBarStyle时,它将无法以此方式工作。它只适用于单个UIViewController。 WWDC 2013视频示例未使用UINavigationController,因此该方法可以正常工作。


你能具体说明一下“正确地将根视图控制器嵌入UINavigationController中”的含义吗?我创建了一个简单的空项目,目前通过storyboard嵌入了一个UIViewController。preferredStatusBarStyle从未被调用过。 - chourobin
1
@chourobin 你说得对。我上面的回答是误导性的。我之所以让它工作,是因为我碰巧设置了UINavigationBar隐藏。在这种情况下,它的行为与根本不使用UINavigationController时相同。 - Strong84
@chourobin 当你试图改变一个位于UINavigationController堆栈中的UIViewController的StatusBarStyle时,它将无法以这种方式工作。它只在单独的UIViewController中起作用。WWDC 2013视频示例没有使用UINavigationController,所以这种方法可以正常工作。你可能想要另一种方式 :) - Strong84

0
与James Frost所说的相反,在花费了很多时间调试我的浏览器活动为什么有错误的状态栏颜色之后(Swift):
override func childViewControllerForStatusBarStyle() -> UIViewController? {
    return visibleViewController
}

话虽如此:在某些情况下,.topViewController 是正确的选择,但在其他情况下,例如 UIActivities,应该使用 .visibleViewController。


0

我尝试了其他解决方案并注意到状态栏在没有setNeedsStatusBarAppearanceUpdate()的情况下不会更新。可以有多个地方调用此标记,但最简单的方法是覆盖viewControllers setter。

class StatusBarNavigationController: UINavigationController {
    override var childForStatusBarHidden: UIViewController? {
        return topViewController
    }

    override var viewControllers: [UIViewController] {
        didSet { setNeedsStatusBarAppearanceUpdate() }
    }
}

然后您可以在代码中或Storyboard中使用StatusBarNavigationController


0
感谢 @James Frost 的帮助,这个解决方案很好用。
起初我没有使其工作,所以我想进一步解释一下。

如果你有一个UINavigationController子类,那么在你的子类中同时添加preferredStatusBarStyle是很重要的。

- (UIStatusBarStyle)preferredStatusBarStyle
{
  return UIStatusBarStyleLightContent;
}

在 UINavigationController 的扩展中添加 childViewControllerForStatusBarStyle
extension UINavigationController {
  override open var childViewControllerForStatusBarStyle: UIViewController? {
    return visibleViewController
  }
}

顺便说一下,UINavigationController的子类和UINavigationController的扩展可以使用不同的编程语言,但仍然可以正常工作。


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