UIStatusBarStyle PreferredStatusBarStyle在iOS 7上不起作用

时间:2013-10-01 05:19:02

标签: iphone ios7 xcode5 uistatusbar

在使用适用于iOS 7的Xcode 5构建的iPhone应用程序中,我在UIViewControllerBasedStatusBarAppearance=YES中设置了info.plist,在我的ViewController中设置了此代码:

-(UIStatusBarStyle) preferredStatusBarStyle
{
    return UIStatusBarStyleLightContent;
}

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

我知道可以通过在UIViewControllerBasedStatusBarAppearance=NO中设置info.plist来更改此应用范围,但实际上我需要在运行时以viewController viewController为基础更改此设置

17 个答案:

答案 0 :(得分:275)

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

将navigationBar的barStyle设置为UIBarStyleBlackTranslucent会提供白色状态栏文字(例如UIStatusBarStyleLightContent),而UIBarStyleDefault会显示黑色状态栏文字(即。{{ 1}})。

注意即使您通过UIStatusBarStyleDefault完全更改了navigationBar的颜色,这也适用。

答案 1 :(得分:86)

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

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

现在我可以将状态栏设置为白色或黑色。

答案 2 :(得分:68)

要让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
    }

}

答案 3 :(得分:33)

我可能会迟到一点,但是其他任何人都在寻找一个有效且经过验证的应用程序范围的解决方案。

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

delta(B)

此代码简单地提取第一个视图控制器(根视图控制器)并将其解包(在obj-c中只检查它不是nil)。如果unwrap成功(不是nil),那么我们获取rootViewControllers preferredStatusBarStyle。否则我们只返回默认值。

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

答案 4 :(得分:21)

要在接受的答案中提供更多详细信息,请在应用代理的didFinishLaunchingWithOptions:方法中添加以下行:

[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;

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

如果你想为整个应用程序提供相同的状态栏颜色,我相信它应该如何完成,而不是从导航控制器完成。您可能拥有不一定嵌入UINavigationController或其他地方的UINavigationController子类的屏幕,以及其他内容。

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

答案 5 :(得分:10)

在viewDidLoad中写下这个

[self setNeedsStatusBarAppearanceUpdate];

就这样做,它会起作用

请你试试这个

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

我在你的问题中看到的另一件事是 你已经写过像这样的方法

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

但它应该是这样的

-(UIStatusBarStyle)preferredStatusBarStyle{ 
    return UIStatusBarStyleLightContent; 
} 

答案 6 :(得分:5)

以下是我如何解决它。通常,navigationController或tabBarController是决定状态栏外观(隐藏,颜色等)的那些。

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

触发状态栏外观更新的方法是调用setNeedsStatusBarAppearanceUpdate,再次触发preferredStatusBarStyle并根据方法返回的内容更新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
    }
}

答案 7 :(得分:4)

即使有了所有的答案,我仍然没有找到适合我的解决方案,但是从Daniel的回答开始。我最终得到的是:

override var preferredStatusBarStyle: UIStatusBarStyle {
     return visibleViewController?.preferredStatusBarStyle ?? .lightContent
}
导航控制器中的

(类似于tab,只是selectedViewController)。然后它会尊重:

override var preferredStatusBarStyle: UIStatusBarStyle {
     return .lightContent
}

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

答案 8 :(得分:3)

iOS 13解决方案

投票最多的答案使用“旧版”代码?

现在(iOS 13+)设置barStyle属性被视为“旧版自定义”。 According to Apple

  

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

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

UINavigationControllerUIViewController(谁知道?)的子类!

因此,当展示嵌入在导航控制器中的视图控制器时,并不是真正展示嵌入的视图控制器;您正在展示导航控制器! UINavigationController作为UIViewController的子类,继承了preferredStatusBarStylechildForStatusBarStyle,您可以根据需要设置它们。

以下任何一种方法都可以使用:

  1. preferredStatusBarStyle内覆盖UINavigationController

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

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

      OR

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

    • childForStatusBarStyledoc)-在系统需要视图控制器用于确定状态栏样式时调用
    • 根据Apple的文档,
        

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

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

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

      OR

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

      • {{1}中的topViewControllerdoc)-导航堆栈顶部的视图控制器
      • UINavigationController(共visibleViewController个)(doc)-与导航界面中当前可见视图关联的视图控制器(提示:这可以包括“已显示的视图控制器在导航控制器本身的顶部”)

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

P.S。我的代码使用Swift 5.1语法?

答案 9 :(得分:3)

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

如果可用,请从info.plist中删除UIViewControllerBasedStatusBarAppearance键值对,或设置NO而不删除它。如果它在info.plist中不可用,则不执行任何操作。此属性的默认值为NO

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

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

2)不同视图控制器的不同设置:

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

如果您的View Controller未嵌入导航控制器。让我们说MyViewController。只需将下面的代码添加到MyViewController.m文件中即可。如果您的View Controller嵌入到Navigation Controller中,请创建一个新的Cocoa Touch类并使其成为UINavigationController的子类。让我们说MyNC。在右侧窗格的故事板上选择导航控制器视图;实用程序 - &gt;身份检查员 - &gt;自定义类 - &gt;类,输入“MyNC”。将Storyboard View与您的“MyNC”Cocoa Touch Class相关联后,请将以下代码添加到您的MyNC.m中:

- (BOOL)prefersStatusBarHidden {
    return NO;
}

-(UIStatusBarStyle)preferredStatusBarStyle {
    return UIStatusBarStyleLightContent;
}

答案 10 :(得分:2)

Swift 4.2

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

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

答案 11 :(得分: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;
}

答案 12 :(得分:1)

swift例子

在AppDelegate.swift

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

    return true
}

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

答案 13 :(得分:1)

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

[[UIApplication sharedApplication]setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
[[UIApplication sharedApplication]setStatusBarStyle:UIStatusBarStyleLightContent];

答案 14 :(得分:0)

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

此注释可能会帮助结构相似的其他人!因此,基本上,您可以在新UIWindow的ViewController中应用上述解决方案。

再次针对这种情况。

谢谢

答案 15 :(得分:0)

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

-(UIStatusBarStyle)preferredStatusBarStyle{
    return UIStatusBarStyleBlackOpaque;
}

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

if([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0f)
    {
       [self setNeedsStatusBarAppearanceUpdate];
    }

答案 16 :(得分:-1)

对于swift 3,在你的UIViewController中:

override var preferredStatusBarStyle : UIStatusBarStyle { return UIStatusBarStyle.lightContent }