代码之家  ›  专栏  ›  技术社区  ›  Andrew Smith

UIStatusBarStyle首选状态BarStyle在iOS 7上不起作用

  •  111
  • Andrew Smith  · 技术社区  · 11 年前

    在我用Xcode 5为iOS 7构建的iPhone应用程序中,我设置了 UIViewControllerBasedStatusBarAppearance=YES 在里面 info.plist ,在我的 ViewController 我有这个代码:

    -(UIStatusBarStyle) preferredStatusBarStyle
    {
        return UIStatusBarStyleLightContent;
    }
    

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

    我知道可以通过设置在整个应用程序范围内更改此应用程序 UIViewControllerBasedStatusBarAppearance=NO 在里面 信息.plist ,但实际上我需要在 viewController 通过 视图控制器 在运行时基于。

    19 回复  |  直到 8 年前
        1
  •  281
  •   mxcl    11 年前

    我发现,如果您的ViewController位于navigationController中,则navigationControllers navigationBar.barStyle 确定状态BarStyle。

    设置导航栏 barStyle UIBarStyleBlackTranslucent 将给出白色状态栏文本(即。 UIStatusBarStyleLightContent ),以及 UIBarStyleDefault 将给出黑色状态栏文本(即。 UIStatusBarStyleDefault ).

    笔记 即使您通过其 barTintColor .

        2
  •  88
  •   Sahil Kapoor    8 年前

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

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

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

        3
  •  77
  •   Daniel Wood    6 年前

    对于 preferredStatusBarStyle() 在内部工作 UINavigationController UITabBarController 我添加了以下代码,它将从当前可见的视图控制器中获得首选的状态栏样式。

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

    对于 雨燕3 这些不是方法,而是财产:

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

    这个 雨燕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
        }
    
    }
    
        4
  •  33
  •   Cœur Gustavo Armenta    8 年前

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

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

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

    这段代码只是提取第一个视图控制器(根视图控制器)并打开它(在obj-c中,只检查它是否为nil)。如果打开成功(不是零),那么我们获取rootViewControllers preferredStatusBarStyle。否则,我们只返回默认值。

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

        5
  •  21
  •   Community CDub    7 年前

    要为已接受的答案提供更多详细信息,请在应用程序代表的 didFinishLaunchingWithOptions: 方法:

    [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;
    

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

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

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

        6
  •  10
  •   BhavikKama    11 年前

    在视图中DidLoad只需写下以下内容

    [self setNeedsStatusBarAppearanceUpdate];
    

    只要这样做就会奏效

    你能试试这个吗

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

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

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

    但应该是这样

    -(UIStatusBarStyle)preferredStatusBarStyle{ 
        return UIStatusBarStyleLightContent; 
    } 
    
        7
  •  9
  •   Andrew Kirna    5 年前

    iOS 13解决方案

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

    设置 barStyle 属性现在(iOS 13+)被认为是“遗留定制” According to Apple ,

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

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

    UINavigationController 是的子类 UIViewController (谁知道的)!

    因此,当呈现嵌入导航控制器中的视图控制器时,并不是真正呈现嵌入的视图控制器;你正在展示导航控制器! UI导航控制器 ,作为的子类 UI视图控制器 ,继承 preferredStatusBarStyle childForStatusBarStyle ,您可以根据需要进行设置。

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

    1. 以(权力)否决 首选状态栏样式 在内部 UI导航控制器

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

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

        extension UINavigationController {
            open override var preferredStatusBarStyle: UIStatusBarStyle {
                .lightContent
            }
        }
        
    2. 以(权力)否决 状态栏样式的子项 在内部 UI导航控制器

      • 状态栏样式的子项 ( doc )-当系统需要视图控制器来确定状态栏样式时调用
      • 根据苹果公司的文件,

        如果容器视图控制器的状态栏样式是从它的一个子视图控制器派生的,请[重写此属性]并返回该子视图控制器。如果返回nil或不重写此方法,则使用self的状态栏风格。如果此方法的返回值更改,请调用setNeedsStatusBarAppearanceUpdate()方法

      • 换句话说,如果您不在这里实现解决方案3,系统将回到上面的解决方案2。
      • 子类或扩展 UI导航控制器

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

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

        • topViewController (第页,共页) UI导航控制器 ) ( doc )-导航堆栈顶部的视图控制器
        • visibleViewController (第页,共页) UI导航控制器 ) ( doc )-与导航界面中当前可见视图相关联的视图控制器(提示:这可以包括“在导航控制器本身之上以模式显示的视图控制器”)

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

    附言:我的代码使用Swift 5.1语法

        8
  •  6
  •   aryaxt    8 年前

    以下是我解决问题的方法。通常navigationController或tabBarController决定状态栏的外观(隐藏、颜色等)。

    因此,我最终对导航控制器进行了子类化,并覆盖了preferredStatusBarStyle。如果当前可见的ViewContorler实现了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
        }
    }
    
        9
  •  6
  •   Andrew Plummer    8 年前

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

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

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

    override var preferredStatusBarStyle: UIStatusBarStyle {
         return .lightContent
    }
    

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

        10
  •  4
  •   Fatih Aksu    9 年前

    1) 整个项目一个设置:

    如果可用,请删除 UIViewControllerBasedStatusBarAppearance info.plist或集合中的键值对 NO 不删除它。如果它在你的info.plist中不可用,什么也不做。默认值为 对于此属性。

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

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

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

    添加 UIViewControllerBasedStatusBar外观 将键值对添加到info.plist中,并将其设置为 YES .

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

    - (BOOL)prefersStatusBarHidden {
        return NO;
    }
    
    -(UIStatusBarStyle)preferredStatusBarStyle {
        return UIStatusBarStyleLightContent;
    }
    
        11
  •  1
  •   aalesano    11 年前

    如果您想在splashScreen期间隐藏状态栏,但又想将样式更改为轻内容(StatusBarInitialyHidden on Plist必须为NO才能在splash时隐藏状态栏),则可以将其添加到appDelegate的didFinishLaunchingWithOptions方法中,以更改为轻属性。

    [[UIApplication sharedApplication]setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
    [[UIApplication sharedApplication]setStatusBarStyle:UIStatusBarStyleLightContent];
    
        12
  •  1
  •   fyalavuz    10 年前

    迅速的例子

    在AppDelegate.swift中

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

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

        13
  •  1
  •   Cœur Gustavo Armenta    8 年前

    如果您正在使用 NavigationController ,您可以将 导航控制器 以便它咨询其子视图控制器

    //我的自定义导航控制器

    - (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;
    }
    
        14
  •  1
  •   Vyacheslav    6 年前

    雨燕4.2

    extension UITabBarController {
        open override var childForStatusBarStyle: UIViewController? {
            return selectedViewController
        }
    }
    
    extension UINavigationController {
        open override var childForStatusBarStyle: UIViewController? {
            return visibleViewController
        }
    }
    
        15
  •  0
  •   Ganapathy    11 年前

    您可以设置状态栏样式。它将类似于IOS6及以下版本的状态栏。
    将这些方法粘贴到视图控制器中

    -(UIStatusBarStyle)preferredStatusBarStyle{
        return UIStatusBarStyleBlackOpaque;
    }
    

    并从视图中调用此方法,加载方式如下

    if([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0f)
        {
           [self setNeedsStatusBarAppearanceUpdate];
        }
    
        16
  •  0
  •   fyalavuz    10 年前

    迅速的例子

    func应用程序(应用程序:UIApplication,didFinishLaunchingWithOptions启动选项:NSDictionary?)->布尔{ UIApplication.sharedApplication().statusBarStyle=UIStatusBarStyl.LightContent;

        return true
    }
    

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

        17
  •  0
  •   Ehab Saifan    6 年前

    我只想为我面对的一个具体案例补充一点说明。我的应用程序中有另一个UIWindow,可以显示一个聊天脸,让它一直漂浮在我的应用软件上。这样做导致上面的解决方案都不起作用,我真的不确定为什么!我所注意到的是,我在新UIWindow中的ViewController就是原因!如果我想更改状态栏样式,我必须在新UIWindow的视图控制器中进行。

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

    同样,这是一个具体的案例。

    谢谢

        18
  •  0
  •   Eugene    2 年前

    想要一些技巧吗?无需覆盖每个视图控制器中的状态栏样式

    第一:跟随@ Sahil Kapoor ,将“查看基于控制器的状态栏=是”添加到plist

    第二:创建窗口的根视图控制器的子类,并返回StatusBarTrackingController。

    final class StatusBarTracker: UIViewController {
        override var preferredStatusBarStyle: UIStatusBarStyle {
            CustomThemeProvider.currentTheme.asStatusBarStyle
        }
    }
    
    final class TabBarController: UITabBarController {
         private let statusBarTracker = StatusBarTracker()
    
         override var childForStatusBarStyle: UIViewController? {
            statusBarTracker
        }
    }
    
    extension TabBarController: CustomThemeUpdatable {
        func applyCustomTheme(_ theme: CustomTheme) {
            setNeedsStatusBarAppearanceUpdate()
        }
    }
    
    // SceneDelegate
    window?.rootViewController = TabBarController()
    
        19
  •  -1
  •   laaksom    8 年前

    对于swift 3,在您的UIViewController中:

    override var preferredStatusBarStyle : UIStatusBarStyle { return UIStatusBarStyle.lightContent }