我跟着this thread来覆盖-preferredStatusBarStyle
,但它没有被调用。我可以更改任何选项以启用它吗? (我在我的项目中使用XIB。)
我遇到了同样的问题,并且发现它正在发生,因为我没有在我的应用程序窗口中设置根视图控制器。
我实施UIViewController
的preferredStatusBarStyle
用于UITabBarController
,它控制了屏幕上的视图外观。
当我将根视图控制器设置为指向此UITabBarController
时,状态栏更改开始正常工作,正如预期的那样(并且调用了preferredStatusBarStyle
方法)。
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
... // other view controller loading/setup code
self.window.rootViewController = rootTabBarController;
[self.window makeKeyAndVisible];
return YES;
}
或者,您可以根据需要在每个视图控制器中调用以下方法之一,而不必使用setNeedsStatusBarAppearanceUpdate
:
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
要么
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];
请注意,如果使用此方法,还需要在plist文件中将UIViewControllerBasedStatusBarAppearance
设置为NO
。
除了serenn的答案,如果你使用modalPresentationStyle
(例如.overCurrentContext
)呈现视图控制器,你还应该在新呈现的视图控制器上调用它:
presentedViewController.modalPresentationCapturesStatusBarAppearance = true
不要忘记在显示的视图控制器中覆盖preferredStatusBarStyle
。
如果你的viewController在UINavigationController下。
子类UINavigationController并添加
override var preferredStatusBarStyle: UIStatusBarStyle {
return topViewController?.preferredStatusBarStyle ?? .default
}
将调用ViewController的preferredStatusBarStyle
。
iOS 7中的UIStatusBarStyle
iOS 7中的状态栏是透明的,后面的视图显示出来。
状态栏的样式是指其内容的外观。在iOS 7中,状态栏内容为暗(UIStatusBarStyleDefault
)或浅(UIStatusBarStyleLightContent
)。 UIStatusBarStyleBlackTranslucent
和UIStatusBarStyleBlackOpaque
都在iOS 7.0中被弃用。请改用UIStatusBarStyleLightContent
。
如何改变UIStatusBarStyle
如果状态栏下方是导航栏,则会调整状态栏样式以匹配导航栏样式(UINavigationBar.barStyle
):
具体来说,如果导航栏样式为UIBarStyleDefault,则状态栏样式为UIStatusBarStyleDefault
;如果导航栏样式是UIBarStyleBlack
,状态栏样式将是UIStatusBarStyleLightContent
。
如果状态栏下方没有导航栏,则应用程序运行时,各个视图控制器可以控制和更改状态栏样式。
-[UIViewController preferredStatusBarStyle]
是iOS 7中添加的新方法。可以重写它以返回首选状态栏样式:
- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
如果状态栏样式应由子视图控制器而不是self控制,则覆盖-[UIViewController childViewControllerForStatusBarStyle]
以返回该子视图控制器。
如果您希望选择不使用此行为并使用-[UIApplication statusBarStyle]
方法设置状态栏样式,请将UIViewControllerBasedStatusBarAppearance
键添加到应用程序的Info.plist
文件中,并为其指定值NO。
如果有人使用导航控制器并希望他们的所有导航控制器都具有黑色风格,你可以在Swift 3中编写UINavigationController的扩展,它将适用于所有导航控制器(而不是将其分配给一个控制器)时间)。
extension UINavigationController {
override open func viewDidLoad() {
super.viewDidLoad()
self.navigationBar.barStyle = UIBarStyle.black
}
}
正如selected answer中提到的,根本原因是检查你的窗口根视图控制器对象。
childForStatusBarStyle
使用以下扩展,它处理所有上述情况 -
extension UITabBarController {
open override var childForStatusBarStyle: UIViewController? {
return selectedViewController?.childForStatusBarStyle ?? selectedViewController
}
}
extension UINavigationController {
open override var childForStatusBarStyle: UIViewController? {
return topViewController?.childForStatusBarStyle ?? topViewController
}
}
extension AppRootViewController {
open override var preferredStatusBarStyle: UIStatusBarStyle {
return children.first { $0.childForStatusBarStyle != nil }?.childForStatusBarStyle?.preferredStatusBarStyle ?? .default
}
}
UIViewControllerBasedStatusBarAppearance
中使用info.plist
键,因为它默认为trueNewFlowUIViewController
然后将新导航或tabBar控制器添加到NewFlowUIViewController
,然后添加NewFlowUIViewController
的扩展以管理更多视图控制器的状态栏样式。fullScreen
之外的modalPresentationStyle,则必须将modalPresentationCapturesStatusBarAppearance
设置为true,以便呈现的视图控制器必须接收状态栏外观控件。在Swift中用于任何类型的UIViewController:
在你的AppDelegate
集:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
window!.rootViewController = myRootController
return true
}
myRootController
可以是任何种类的UIViewController
,例如UITabBarController
或UINavigationController
。
然后,像这样覆盖这个根控制器:
class RootController: UIViewController {
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return .LightContent
}
}
这将改变整个应用程序中状态栏的外观,因为根控制器全权负责状态栏的外观。
请记住在View controller-based status bar appearance
中将属性Info.plist
设置为YES以使其工作(这是默认设置)。
Swift 3 iOS 10解决方案:
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
这是我解决这个问题的方法。
定义一个名为AGViewControllerAppearance的协议。
AGViewControllerAppearance.h
#import <Foundation/Foundation.h>
@protocol AGViewControllerAppearance <NSObject>
@optional
- (BOOL)showsStatusBar;
- (BOOL)animatesStatusBarVisibility;
- (UIStatusBarStyle)preferredStatusBarStyle;
- (UIStatusBarAnimation)prefferedStatusBarAnimation;
@end
在UIViewController上定义一个名为Upgrade的类别。
的UIViewController + Upgrade.h
#import <UIKit/UIKit.h>
@interface UIViewController (Upgrade)
//
// Replacements
//
- (void)upgradedViewWillAppear:(BOOL)animated;
@end
的UIViewController + Upgrade.m
#import "UIViewController+Upgrade.h"
#import <objc/runtime.h>
#import "AGViewControllerAppearance.h" // This is the appearance protocol
@implementation UIViewController (Upgrade)
+ (void)load
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wselector"
Method viewWillAppear = class_getInstanceMethod(self, @selector(viewWillAppear:));
#pragma clang diagnostic pop
Method upgradedViewWillAppear = class_getInstanceMethod(self, @selector(upgradedViewWillAppear:));
method_exchangeImplementations(viewWillAppear, upgradedViewWillAppear);
}
#pragma mark - Implementation
- (void)upgradedViewWillAppear:(BOOL)animated
{
//
// Call the original message (it may be a little confusing that we're
// calling the 'same' method, but we're actually calling the original one :) )
//
[self upgradedViewWillAppear:animated];
//
// Implementation
//
if ([self conformsToProtocol:@protocol(AGViewControllerAppearance)])
{
UIViewController <AGViewControllerAppearance> *viewControllerConformingToAppearance =
(UIViewController <AGViewControllerAppearance> *)self;
//
// Status bar
//
if ([viewControllerConformingToAppearance respondsToSelector:@selector(preferredStatusBarStyle)])
{
BOOL shouldAnimate = YES;
if ([viewControllerConformingToAppearance respondsToSelector:@selector(animatesStatusBarVisibility)])
{
shouldAnimate = [viewControllerConformingToAppearance animatesStatusBarVisibility];
}
[[UIApplication sharedApplication] setStatusBarStyle:[viewControllerConformingToAppearance preferredStatusBarStyle]
animated:shouldAnimate];
}
if ([viewControllerConformingToAppearance respondsToSelector:@selector(showsStatusBar)])
{
UIStatusBarAnimation animation = UIStatusBarAnimationSlide;
if ([viewControllerConformingToAppearance respondsToSelector:@selector(prefferedStatusBarAnimation)])
{
animation = [viewControllerConformingToAppearance prefferedStatusBarAnimation];
}
[[UIApplication sharedApplication] setStatusBarHidden:(! [viewControllerConformingToAppearance showsStatusBar])
withAnimation:animation];
}
}
}
@end
现在,是时候说你的视图控制器正在实现AGViewControllerAppearance协议。
例:
@interface XYSampleViewController () <AGViewControllerAppearance>
... the rest of the interface
@end
当然,您可以从协议中实现其余的方法(showsStatusBar,animatesStatusBarVisibility,prefferedStatusBarAnimation),UIViewController + Upgrade将根据它们提供的值进行正确的自定义。
如果有人用UISearchController遇到这个问题。只需创建一个新的UISearchController子类,然后将下面的代码添加到该类中:
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return .LightContent
}
请注意,使用self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
解决方案时
一定要去你的plist并将“查看基于控制器的状态栏外观”设置为YES。如果它不,它将无法正常工作。
对于使用UINavigationController的任何人:
UINavigationController
没有转发preferredStatusBarStyle
呼叫其子视图控制器。相反,它管理自己的状态 - 正如它应该的那样,它绘制在状态栏所在的屏幕顶部,因此应该负责它。因此,在导航控制器内的VC中实现preferredStatusBarStyle
将不会做任何事情 - 它们永远不会被调用。
诀窍是UINavigationController
用来决定返回UIStatusBarStyleDefault
或UIStatusBarStyleLightContent
的内容。它的基础是它的UINavigationBar.barStyle
。默认(UIBarStyleDefault
)导致黑暗前景UIStatusBarStyleDefault
状态栏。而UIBarStyleBlack
将给出一个UIStatusBarStyleLightContent
状态栏。
TL; DR:
如果你想在UIStatusBarStyleLightContent
上使用UINavigationController
:
self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
大多数答案不包括childViewControllerForStatusBarStyle
的UINavigationController
方法的良好实施。根据我的经验,您应该处理在导航控制器上显示透明视图控制器时的情况。在这些情况下,您应该将控制传递给模态控制器(visibleViewController
),但不会在它消失时传递。
override var childViewControllerForStatusBarStyle: UIViewController? {
var childViewController = visibleViewController
if let controller = childViewController, controller.isBeingDismissed {
childViewController = topViewController
}
return childViewController?.childViewControllerForStatusBarStyle ?? childViewController
}
NavigationController或TabBarController是需要提供样式的。以下是我的解决方法:https://stackoverflow.com/a/39072526/242769
所以我实际上为UINavigationController添加了一个类别,但使用了这些方法:
-(UIViewController *)childViewControllerForStatusBarStyle;
-(UIViewController *)childViewControllerForStatusBarHidden;
并让那些返回当前可见的UIViewController。这使得当前可见视图控制器设置其自己的首选样式/可见性。
这是一个完整的代码片段:
在Swift中:
extension UINavigationController {
public override func childViewControllerForStatusBarHidden() -> UIViewController? {
return self.topViewController
}
public override func childViewControllerForStatusBarStyle() -> UIViewController? {
return self.topViewController
}
}
在Objective-C中:
@interface UINavigationController (StatusBarStyle)
@end
@implementation UINavigationController (StatusBarStyle)
-(UIViewController *)childViewControllerForStatusBarStyle {
return self.topViewController;
}
-(UIViewController *)childViewControllerForStatusBarHidden {
return self.topViewController;
}
@end
为了更好的衡量,以下是它在UIViewController中的实现方式:
在斯威夫特
override public func preferredStatusBarStyle() -> UIStatusBarStyle {
return .LightContent
}
override func prefersStatusBarHidden() -> Bool {
return false
}
在Objective-C中
-(UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleLightContent; // your own style
}
- (BOOL)prefersStatusBarHidden {
return NO; // your own visibility code
}
最后,确保您的应用程序plist没有将“基于控制器的状态栏外观视图”设置为NO。删除该行或将其设置为YES(我相信现在是iOS 7的默认值?)
对于仍在努力解决这个问题的人来说,swift中的这个简单扩展应该可以解决您的问题。
extension UINavigationController {
override open var childViewControllerForStatusBarStyle: UIViewController? {
return self.topViewController
}
}
Tyson的答案对于在UINavigationController
中将状态栏颜色更改为白色是正确的。
如果有人希望通过在AppDelegate
中编写代码来完成相同的结果,那么使用下面的代码并将其写入AppDelegate's
didFinishLaunchingWithOptions
方法中。
并且不要忘记在.plist文件中将UIViewControllerBasedStatusBarAppearance
设置为YES
,否则更改将不会反映出来。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// status bar appearance code
[[UINavigationBar appearance] setBarStyle:UIBarStyleBlack];
return YES;
}
我的应用程序使用了所有三个:UINavigationController
,UISplitViewController
,UITabBarController
,因此这些似乎都控制了状态栏,并将导致preferedStatusBarStyle
不被称为他们的孩子。要覆盖此行为,您可以像其他提到的答案一样创建扩展。这是Swift 4中所有三个的扩展。希望Apple更清楚这种东西。
extension UINavigationController {
open override var childViewControllerForStatusBarStyle: UIViewController? {
return self.topViewController
}
open override var childViewControllerForStatusBarHidden: UIViewController? {
return self.topViewController
}
}
extension UITabBarController {
open override var childViewControllerForStatusBarStyle: UIViewController? {
return self.childViewControllers.first
}
open override var childViewControllerForStatusBarHidden: UIViewController? {
return self.childViewControllers.first
}
}
extension UISplitViewController {
open override var childViewControllerForStatusBarStyle: UIViewController? {
return self.childViewControllers.first
}
open override var childViewControllerForStatusBarHidden: UIViewController? {
return self.childViewControllers.first
}
}
编辑:更新Swift 4.2 API更改
extension UINavigationController {
open override var childForStatusBarStyle: UIViewController? {
return self.topViewController
}
open override var childForStatusBarHidden: UIViewController? {
return self.topViewController
}
}
extension UITabBarController {
open override var childForStatusBarStyle: UIViewController? {
return self.children.first
}
open override var childForStatusBarHidden: UIViewController? {
return self.children.first
}
}
extension UISplitViewController {
open override var childForStatusBarStyle: UIViewController? {
return self.children.first
}
open override var childForStatusBarHidden: UIViewController? {
return self.children.first
}
}
Hippo答案的补充:如果您使用的是UINavigationController,那么最好添加一个类别:
// UINavigationController+StatusBarStyle.h:
@interface UINavigationController (StatusBarStyle)
@end
// UINavigationController+StatusBarStyle.m:
@implementation UINavigationController (StatusBarStyle)
- (UIStatusBarStyle)preferredStatusBarStyle
{
//also you may add any fancy condition-based code here
return UIStatusBarStyleLightContent;
}
@end
该解决方案可能比转换为即将弃用的行为更好。
对于UINavigationControllers来说,@ serenn的answer仍然很棒。但是,对于swift 3,childViewController函数已更改为vars
。所以UINavigationController
扩展代码应该是:
override open var childViewControllerForStatusBarStyle: UIViewController? {
return topViewController
}
override open var childViewControllerForStatusBarHidden: UIViewController? {
return topViewController
}
然后在视图控制器中应该指定状态栏样式:
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
在UINavigationController上,没有调用preferredStatusBarStyle
,因为它的topViewController
比self
更受欢迎。因此,要在UINavigationController上调用preferredStatusBarStyle
,您需要更改其childViewControllerForStatusBarStyle
。
要为一个UINavigationController(我的推荐)做到这一点:
class MyRootNavigationController: UINavigationController {
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
override var childViewControllerForStatusBarStyle: UIViewController? {
return nil
}
}
要为所有UINavigationController执行此操作(警告:它会影响UIDocumentPickerViewController,UIImagePickerController等):
extension UINavigationController {
open override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
open override var childViewControllerForStatusBarStyle: UIViewController? {
return nil
}
}