如何在带有导航栏的模态视图中更改 iOS 7 中的 UIStatusBarStyle?

Posted

技术标签:

【中文标题】如何在带有导航栏的模态视图中更改 iOS 7 中的 UIStatusBarStyle?【英文标题】:How to change UIStatusBarStyle in iOS 7 in modal views with navigation bar? 【发布时间】:2013-09-30 16:43:25 【问题描述】:

ios 7 Transition Guide 提供了一个很好的提示,如何在 UIViewController 中使用动态更改 UIStatusBarStyle

- (UIStatusBarStyle)preferredStatusBarStyle 
     return UIStatusBarStyleDefault;

[self setNeedsStatusBarAppearanceUpdate];一起

这在单视图应用程序中运行良好。但是,我现在正尝试将模式视图中的UIStatusBarStyle 更改为UIStatusBarStyleLightContent。有一个MainViewControllerModalViewController 相连,而ModalViewController 本身嵌入在NavigationController 中。 ModalViewController 已将其委托设置为 MainViewController

我尝试在ModalViewController 中调用[self setNeedsStatusBarAppearanceUpdate]; 以及该类中的以下方法,但没有效果:

// In ModalViewController.m
- (UIStatusBarStyle)preferredStatusBarStyle 
     return UIStatusBarStyleLightContent;

我还尝试使用- (UIStatusBarStyle)preferredStatusBarStyle 中的条件在prepareForSegue: sender: 方法上的MainViewController 中调用[self setNeedsStatusBarAppearanceUpdate];,以便在显示模式视图时返回UIStatusBarStyleLightContent - 但这也没有效果。

如何在模态视图中更改 UIStatusBarStyle?

编辑: 更新后:我需要提到ModalViewController 嵌入在NavigationControllerNavigationBar 中。将NavigationBar 设置为隐藏到[self setNeedsStatusBarAppearanceUpdate];ModalViewController 中的上述调用可以正常工作。但不是在 Bar 可见时。

【问题讨论】:

您在 ModalViewController 实现中调用 [self setNeedsStatusBarAppearanceUpdate] 的位置是什么? viewDidLoad方法中 -viewWillAppear: 呢? 不适用于viewWillAppear,也不适用于viewDidAppear 我意识到问题出在 NavigationBar(请参阅编辑)。 ModalViewController 中没有导航栏 [self setNeedsStatusBarAppearanceUpdate] 有效 【参考方案1】:

您需要一个全屏显示的 ViewController 来返回适当的状态栏信息。在您的情况下:包含 ModalViewController 的 NavigationController 需要实现 preferredStatusBarStyle 并返回 UIStatusBarStyleLightContent

只有当视图控制器返回的值实际发生变化时,才需要调用setNeedsStatusBarAppearanceUpdate。当视图控制器第一次出现时,无论如何都会查询它们。

【讨论】:

你现在为我节省了很多时间。还需要支持 iOS 6 的 iOS 7 应用程序很难使用。非常感谢! 如何在我的 AppDelegate 中实现 preferredStatusBarStyle?我有一个 TabBarViewController 通向 4 个通向 UIViewControllers 的 NavControllers,我应该在 Tab Bar 的类中尝试这个吗?在导航控制器中?还是在 AppDelegate 中? -我需要将所有状态栏设置为 LightContent 在您的情况下,它可能是 TabBarViewController 的子类,必须实现 preferredStatusBarStyle preferredStatusBarStyle 没有为我调用,因为我使用了UIModalPresentationOverFullScreen 而不是UIModalPresentationOverCurrentContext【参考方案2】:

我们应该注意到非全屏modalVC CAN使用modalPresentationCapturesStatusBarAppearance来控制statusBar样式。

任何想了解更多关于状态栏控件的人都不应忽略UIViewController Managing the Status Bar。

2015-11-06 更新:

并确保您已设置iOS Keys 中描述的UIViewControllerBasedStatusBarAppearance

2018.04.09 更新:

我注意到 navController 中的 viewController 在 iOS 10.0 - 10.2 中可能无法调用 prefersStatusBarHidden。自定义您的 navigationController 以确保

@implementation YourCustomNavController
//for iOS 10.0 - iOS 10.2
- (BOOL)prefersStatusBarHidden 
    UIViewController *childVC = [self childViewControllerForStatusBarHidden];
    if (childVC) 
        return [childVC prefersStatusBarHidden];
    
    return [super prefersStatusBarHidden];

@end

任何想要深入了解的人都可以使用 Hopper 或 IDA Pro 深入了解 UIKit +[UIViewController _currentStatusBarStyleViewController]。它可能会帮助您解决这些类型的错误。

【讨论】:

完美,这正是我面临的问题,自定义呈现的 VC 并没有改变状态栏的外观,而之前的视图仍在查询中。【参考方案3】:

这项工作的关键是只有全屏视图控制器才能决定状态栏的样式。

如果您使用导航控制器并希望在每个视图控制器的基础上控制状态栏,您需要继承 UINavigationController 并实现 preferredStatusBarStyle 以便它返回 topViewController 的首选项。

确保将故事板场景中的类引用从 UINavigationController 更改为您的子类(例如,下面示例中的 MyNavigationController)。

(以下对我有用。如果您的应用是基于 TabBar 的,您可能希望通过继承 UITabBarController 来做类似的事情,但我还没有尝试过)。

@interface MyNavigationController : UINavigationController

@end

@implementation MyNavigationController

- (UIStatusBarStyle)preferredStatusBarStyle

    return self.topViewController.preferredStatusBarStyle;


@end

【讨论】:

子类化 UINavigationController 效果很好,谢谢!我还对一个类别进行了快速实验。它实际上和子类一样有效。【参考方案4】:

要更改嵌入 ViewController 的 UINavigationController 的状态栏而不继承 UINavigationController,请使用以下命令:

navigationController?.navigationBar.barStyle = .Black // to make the status bar text white

.Black 将使文本变为白色(状态栏和视图的标题),而 .Default 具有黑色的标题和状态栏。

【讨论】:

【参考方案5】:

我有一个侧面菜单/显示控制器 (SWRevealController),它始终是状态栏查询的根控制器。覆盖 childViewControllerForStatusBarStyle 让我将查询重新路由到最前面的控制器。

/**
 This view is always considered the topmost for status bar color queries.
 Pass the query along to what we're showing in front.
 */
- (UIViewController *)childViewControllerForStatusBarStyle

    UIViewController *front = self.frontViewController;
    if ([front isKindOfClass:[UINavigationController class]])
        return ((UINavigationController*)front).topViewController;
    else
        return front;

【讨论】:

【参考方案6】:

应用似乎脱离了最顶层 viewController 的 statusBarStyle。因此,如果您在当前视图控制器之上添加另一个视图控制器,它现在会从新视图控制器中获取提示。

【讨论】:

【参考方案7】:

这对我有用:

    View controller-based status bar appearance 设置为NO 将状态栏样式设置为UIStatusBarStyleLightContent(只需复制该值) 在 appDelegate 中使用 [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];

希望对您有所帮助(参考:ios7 status bar changing back to black on modal views?)

【讨论】:

【参考方案8】:

只需查看您的应用的 rootViewController 是否需要覆盖 -(UIStatusBarStyle)preferredStatusBarStyle 方法

【讨论】:

【参考方案9】:

以上所有工作。然而,有时我发现在故事板等中更改每个实例真的很痛苦......所以这里有一些对我有用的东西,它也涉及子类化。

首先创建子类:

@interface HHNavLightColorBarController : UINavigationController

@end

@implementation HHNavLightColorBarController

- (UIStatusBarStyle)preferredStatusBarStyle 
    return UIStatusBarStyleLightContent;

@end

然后使用Objective-C的魔力和一点点

当您有视图控制器的引用并展示它时:

UINavigationController *navVC = ...; // Init in your usual way
object_setClass(navVC, [HHNavLightColorBarController class]);
[self presentViewController:nav animated:YES completion:^
    NSLog(@"Launch Modal View Controller");
];

有时它似乎不那么具有侵入性。您甚至可以创建一个类别来检查您的 kindOfClass 是否是导航控制器并自动为您完成。无论如何,上面的答案是 jaetzold,我只是觉得这很方便。

【讨论】:

以上是关于如何在带有导航栏的模态视图中更改 iOS 7 中的 UIStatusBarStyle?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用导航栏在模态视图中更改iOS 7中的UIStatusBarStyle?

带有透明/模糊导航栏的 iOS 7 视图控制器布局问题

iOS 7:在底部导航栏的表格视图之间滑动

iOS 7 中 UIActivityViewControllers 的模态状态栏和导航栏文本颜色

带有静态导航栏的 UINavigationController

如何更改模态视图 iOS 6 上的状态栏