111

在我用 Xcode 5 for iOS 7 构建的 iPhone 应用程序中,我设置UIViewControllerBasedStatusBarAppearance=YESinfo.plist,并且在我ViewController的代码中:

-(UIStatusBarStyle) preferredStatusBarStyle
{
    return UIStatusBarStyleLightContent;
}

但是状态栏在黑色背景下仍然是黑色的。

我知道可以通过设置更改这个应用程序范围UIViewControllerBasedStatusBarAppearance=NOinfo.plist但我实际上需要在运行时逐个viewController更改它。viewController

4

17 回答 17

281

我发现如果您的 ViewController 在 navigationController 中,那么 navigationController 将navigationBar.barStyle确定 statusBarStyle。

将您的导航栏设置barStyleUIBarStyleBlackTranslucent将给出白色状态栏文本(即。UIStatusBarStyleLightContent),UIBarStyleDefault并将给出黑色状态栏文本(即。UIStatusBarStyleDefault)。

请注意,即使您通过其完全更改导航栏的颜色,这也适用barTintColor

于 2013-10-14T16:49:37.517 回答
87

好的,这是诀窍。您必须添加键“查看基于控制器的状态栏”并将值设置为否。

这与此键的含义相反,但即使您将值设置为No,您仍然可以更改状态栏的外观,以及它是否显示在任何视图控制器中。所以它的行为类似于“是”,但将其设置为“否”!

现在我可以让状态栏变白或变暗。

于 2013-10-19T20:03:18.350 回答
77

为了在其中preferredStatusBarStyle()工作UINavigationControllerUITabBarController我添加了以下代码,它将从当前可见的视图控制器中获取首选的状态栏样式。

extension UITabBarController {
    public override func childViewControllerForStatusBarStyle() -> UIViewController? {
        return selectedViewController
    }
}

extension UINavigationController {
    public override func childViewControllerForStatusBarStyle() -> UIViewController? {
        return visibleViewController
    }
}

对于Swift 3,这些不是方法而是属性:

extension UITabBarController {
    open override var childViewControllerForStatusBarStyle: UIViewController? {
        return selectedViewController
    }
}

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

Swift 4.2属性已重命名:

extension UITabBarController {
   open override var childForStatusBarStyle: UIViewController? {
        return selectedViewController
    }
}

extension UINavigationController {
   open override var childForStatusBarStyle: UIViewController? {
        return visibleViewController
    }
}

用法

class ViewController: UIViewController {

    // This will be called every time the ViewController appears
    // Works great for pushing & popping
    override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }

}
于 2016-06-10T12:36:11.453 回答
33

我可能来晚了一点,但如果其他人正在寻找一个有效且经过验证的应用程序范围的解决方案。

@mxcl 描述了为什么会发生这种情况是正确的。为了更正它,我们只需创建一个扩展(或 obj-c 中的类别)来覆盖 UINavigationController 的 preferredSatusBarStyle() 方法。这是 Swift 中的一个示例:

extension UINavigationController {
    public override func preferredStatusBarStyle() -> UIStatusBarStyle {
        if let rootViewController = self.viewControllers.first {
            return rootViewController.preferredStatusBarStyle()
        }
        return super.preferredStatusBarStyle()
    }
}

这段代码简单地提取第一个视图控制器(根视图控制器)并将其解包(在 obj-c 中只需检查它是否不为零)。如果解包成功(不是 nil),那么我们获取 rootViewControllers 的首选状态栏样式。否则我们只返回默认值。

希望这可以帮助任何可能需要它的人。

于 2015-06-11T03:39:23.840 回答
21

要为接受的答案提供更多详细信息,请在您的应用程序委托的didFinishLaunchingWithOptions:方法中添加以下行:

[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;

然后,在您的 Info.plist 中,添加View controller-based status bar appearance并将其设置为NO.

如果您希望整个应用程序的状态栏颜色相同,我相信应该这样做,而不是从导航控制器。您可能有不一定嵌入到 a或其他地方UINavigationController的不同子类中的屏幕以及其他东西。UINavigationController

编辑:您也可以在不输入任何代码的情况下执行此操作:https ://stackoverflow.com/a/18732865/855680

于 2013-12-06T04:21:55.417 回答
10

在 viewDidLoad 中只写这个

[self setNeedsStatusBarAppearanceUpdate];

就这样做,它会工作

你能试试这个吗

Set UIViewControllerBasedStatusBarAppearance to NO.
Call [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];

我在您的问题中看到的另一件事是您编写了这样的方法

 -(void)UIStatusBarStyle PreferredStatusBarStyle ()
        {
            return UIStatusBarStyle.LightContent;
        }

但应该是这样的

-(UIStatusBarStyle)preferredStatusBarStyle{ 
    return UIStatusBarStyleLightContent; 
} 
于 2013-10-01T05:29:16.143 回答
7

iOS 13 解决方案

投票最高的答案使用“遗留”代码

设置barStyle属性现在(iOS 13+)被认为是“遗留自定义”。据苹果称

在 iOS 13 及更高版本中,使用 standardAppearance、compactAppearance 和 scrollEdgeAppearance 属性自定义导航栏。您可以继续使用这些旧访问器直接自定义导航栏的外观,但您必须自己更新不同栏配置的外观。

关于您的尝试-您走在正确的轨道上!

UINavigationControllerUIViewController(谁知道)的子类!

因此,当呈现嵌入在导航控制器中的视图控制器时,您并没有真正呈现嵌入的视图控制器。您正在展示导航控制器!UINavigationController, 作为 , 的子类UIViewController, 继承preferredStatusBarStylechildForStatusBarStyle, 您可以根据需要进行设置。

以下任何一种方法都应该有效:

  1. 覆盖preferredStatusBarStyle范围内UINavigationController

    • preferredStatusBarStyle( doc ) - 视图控制器的首选状态栏样式
    • 子类或扩展UINavigationController

      class MyNavigationController: UINavigationController {
          override var preferredStatusBarStyle: UIStatusBarStyle {
              .lightContent
          }
      }
      

      或者

      extension UINavigationController {
          open override var preferredStatusBarStyle: UIStatusBarStyle {
              .lightContent
          }
      }
      
  2. 覆盖childForStatusBarStyle范围内UINavigationController

    • childForStatusBarStyle( doc ) - 当系统需要视图控制器用于确定状态栏样式时调用
    • 根据苹果的文档,

      “如果您的容器视图控制器从其子视图控制器之一派生其状态栏样式,[覆盖此属性]并返回该子视图控制器。如果您返回 nil 或不覆盖此方法,则使用 self 的状态栏样式. 如果此方法的返回值发生变化,请调用 setNeedsStatusBarAppearanceUpdate() 方法。"

    • 换句话说,如果您在此处不执行解决方案 3,系统将回退到上面的解决方案 2。
    • 子类或扩展UINavigationController

      class MyNavigationController: UINavigationController {
          override var childForStatusBarStyle: UIViewController? {
              topViewController
          }
      }
      

      或者

      extension UINavigationController {    
          open override var childForStatusBarStyle: UIViewController? {
              topViewController
          }
      }
      
    • 您可以在上面返回您想要的任何视图控制器。我推荐以下之一:

      • topViewController(of UINavigationController) ( doc ) - 位于导航堆栈顶部的视图控制器
      • visibleViewController(of UINavigationController) ( doc ) - 与导航界面中当前可见视图相关联的视图控制器(提示:这可以包括“以模态方式呈现在导航控制器本身之上的视图控制器”)

注意:如果您决定子类UINavigationController化,请记住通过 IB 中的身份检查器将该类应用于您的导航控制器。

PS 我的代码使用 Swift 5.1 语法

于 2019-10-24T15:47:45.363 回答
6

即使这里有所有答案,我仍然没有找到适合我的确切解决方案,而是从丹尼尔的答案开始。我最终得到的是:

override var preferredStatusBarStyle: UIStatusBarStyle {
     return visibleViewController?.preferredStatusBarStyle ?? .lightContent
}

在导航控制器中(类似于选项卡,只是 selectedViewController)。然后它将尊重:

override var preferredStatusBarStyle: UIStatusBarStyle {
     return .lightContent
}

在每个视图控制器中,除非您另行设置。我不需要在setNeedsStatusBarAppearanceUpdate()任何地方打电话,它只会在您到达每个视图控制器时更新。

于 2017-03-22T04:07:11.937 回答
6

这是我解决它的方法。通常,navigationController 或 tabBarController 决定状态栏的外观(隐藏、颜色等)。

所以我最终继承了导航控制器并覆盖了preferredStatusBarStyle。如果当前可见的 ViewContorller 实现了 StatusBarStyleHandler 我要求将值用作样式,如果不是,我只返回一个默认值。

触发状态栏外观更新的方式是再次调用setNeedsStatusBarAppearanceUpdatewhich triggerspreferredStatusBarStyle并根据方法返回的内容更新 UI

public protocol StatusBarStyleHandler {
    var preferredStatusBarStyle: UIStatusBarStyle { get }
}

public class CustomNavigationCotnroller: UINavigationController {

    public override var preferredStatusBarStyle: UIStatusBarStyle {
        if let statusBarHandler = visibleViewController as? StatusBarStyleHandler {
            return statusBarHandler.preferredStatusBarStyle
        }

        return .default
    }
}

然后使用

public class SomeController: UIViewController, StatusBarStyleHandler {

    private var statusBarToggle = true

    // just a sample for toggling the status bar style each time method is called
    private func toggleStatusBarColor() {
        statusBarToggle = !statusBarToggle
        setNeedsStatusBarAppearanceUpdate()
    }

    public override var preferredStatusBarStyle: UIStatusBarStyle {
        return statusBarToggle ? .lightContent : .default
    }
}
于 2016-08-22T06:22:46.943 回答
4

1)整个项目的一种设置:

如果可用,UIViewControllerBasedStatusBarAppearance请从 info.plist 中删除键值对,或设置NO而不删除它。如果它在您的 info.plist 中不可用,则什么也不做。默认NO为该属性。

将以下代码添加到您的 AppDelegate.m:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
}

2)不同View Controller的不同设置:

UIViewControllerBasedStatusBarAppearance键值对添加到您的 info.plist 并将其设置为YES.

如果您的视图控制器未嵌入到导航控制器中。假设 MyViewController。只需将下面的代码添加到您的 MyViewController.m 文件中。如果您的 View Controller 嵌入到 Navigation Controller 中,请创建一个新的 Cocoa Touch 类并使其成为 UINavigationController 的子类。假设 MyNC。在 Storyboard 的右窗格中选择 Navigation Controller View;实用程序 -> 身份检查器 -> 自定义类 -> 类,键入“MyNC”。将 Storyboard View 与您的“MyNC”Cocoa Touch 类链接后,将以下代码添加到您的 MyNC.m:

- (BOOL)prefersStatusBarHidden {
    return NO;
}

-(UIStatusBarStyle)preferredStatusBarStyle {
    return UIStatusBarStyleLightContent;
}
于 2015-11-05T11:40:01.260 回答
1

如果您想在 splashScreen 期间隐藏 statusBar 但想要将样式更改为浅色内容(Plist 上的 StatusBarInitiallyHidden 必须为 NO 才能在 splash 上隐藏 statusBar),您可以将其添加到 appDelegate 的 didFinishLaunchingWithOptions 方法以更改为 lightContent。

[[UIApplication sharedApplication]setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
[[UIApplication sharedApplication]setStatusBarStyle:UIStatusBarStyleLightContent];
于 2014-02-08T15:50:17.337 回答
1

快速示例

在 AppDelegate.swift

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
    UIApplication.sharedApplication().statusBarStyle = UIStatusBarStyle.LightContent;

    return true
}

在 info.plist 中设置查看基于控制器的状态栏外观:NO

于 2014-07-25T09:35:15.790 回答
1

如果您正在使用NavigationController,则可以子类化NavigationController,以便它咨询其子视图控制器

// MyCustomNavigationController

- (NSUInteger)supportedInterfaceOrientations {
    UIViewController *viewControllerToAsk = [self findChildVC];
    return [viewControllerToAsk supportedInterfaceOrientations];
}

- (BOOL)shouldAutorotate {
    UIViewController *viewControllerToAsk = [self findChildVC];
    return [viewControllerToAsk shouldAutorotate];
}

- (UIStatusBarStyle)preferredStatusBarStyle {
    UIViewController *viewControllerToAsk = [self findChildVC];
    return [viewControllerToAsk preferredStatusBarStyle];
}

- (UIViewController *)findChildVC {
    return self.viewControllers.firstObject;
}
于 2015-05-06T08:48:43.983 回答
1

斯威夫特 4.2

extension UITabBarController {
    open override var childForStatusBarStyle: UIViewController? {
        return selectedViewController
    }
}

extension UINavigationController {
    open override var childForStatusBarStyle: UIViewController? {
        return visibleViewController
    }
}
于 2018-07-19T14:45:06.440 回答
0

您可以设置状态栏样式。它将类似于 IOS 6 及更低版本的状态栏。
将此方法粘贴到您的视图控制器中

-(UIStatusBarStyle)preferredStatusBarStyle{
    return UIStatusBarStyleBlackOpaque;
}

并从视图中调用此方法确实像这样加载

if([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0f)
    {
       [self setNeedsStatusBarAppearanceUpdate];
    }
于 2013-10-01T05:48:29.937 回答
0

我只想为我遇到的特定案例添加注释。我的应用程序中有另一个 UIWindow 来显示一直在我的应用程序中浮动的聊天面孔。这样做会导致上述解决方案都不起作用,我不确定为什么!我所注意到的是,我在新 UIWindow 中的 ViewController 是造成这种情况的原因!如果我想更改状态栏样式,我必须在新 UIWindow 的视图控制器中进行。

这篇笔记可能会对其他有类似结构的人有所帮助!所以基本上你可以在新的 UIWindow 的 ViewController 中应用上面提到的解决方案。

这又是一个具体案例。

谢谢

于 2018-10-12T15:19:30.353 回答
-1

对于 swift 3,在您的 UIViewController 中:

override var preferredStatusBarStyle : UIStatusBarStyle { return UIStatusBarStyle.lightContent }
于 2017-02-02T14:23:02.787 回答