ios 未调用 preferredStatusBarStyle

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19022210/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 01:43:20  来源:igfitidea点击:

preferredStatusBarStyle isn't called

iosios7uikituistatusbar

提问by trgoofi

I followed this threadto override -preferredStatusBarStyle, but it isn't called. Are there any options that I can change to enable it? (I'm using XIBs in my project.)

我按照这个线程来覆盖-preferredStatusBarStyle,但它没有被调用。是否有任何选项可以更改以启用它?(我在我的项目中使用 XIB。)

采纳答案by AbdullahC

Possible root cause

可能的根本原因

I had the same problem, and figured out it was happening because I wasn't setting the root view controller in my application window.

我遇到了同样的问题,并发现它正在发生,因为我没有在我的应用程序窗口中设置根视图控制器。

The UIViewControllerin which I had implemented the preferredStatusBarStylewas used in a UITabBarController, which controlled the appearance of the views on the screen.

UIViewController,其中我已经实现的preferredStatusBarStyle是在一个使用UITabBarController,其控制的屏幕上的意见的外观。

When I set the root view controller to point to this UITabBarController, the status bar changes started to work correctly, as expected (and the preferredStatusBarStylemethod was getting called).

当我将根视图控制器设置为指向 this 时UITabBarController,状态栏更改开始按预期正常工作(并且该preferredStatusBarStyle方法被调用)。

(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    ... // other view controller loading/setup code

    self.window.rootViewController = rootTabBarController;
    [self.window makeKeyAndVisible];
    return YES;
}

Alternative method (Deprecated in iOS 9)

替代方法(在 iOS 9 中已弃用)

Alternatively, you can call one of the following methods, as appropriate, in each of your view controllers, depending on its background color, instead of having to use setNeedsStatusBarAppearanceUpdate:

或者,您可以根据背景颜色在每个视图控制器中调用以下方法之一,而不必使用setNeedsStatusBarAppearanceUpdate

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];

or

或者

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];

Note that you'll also need to set UIViewControllerBasedStatusBarAppearanceto NOin the plist file if you use this method.

请注意,如果您使用此方法,您还需要在 plist 文件中设置UIViewControllerBasedStatusBarAppearanceNO

回答by Tyson

For anyone using a UINavigationController:

对于使用 UINavigationController 的任何人:

The UINavigationControllerdoes not forward on preferredStatusBarStylecalls to its child view controllers. Instead it manages its own state - as it should, it is drawing at the top of the screen where the status bar lives and so should be responsible for it. Therefor implementing preferredStatusBarStylein your VCs within a nav controller will do nothing - they will never be called.

UINavigationController不转发就preferredStatusBarStyle调用它的子视图控制器。相反,它管理自己的状态——它应该在屏幕顶部绘制状态栏所在的位置,因此应该对其负责。因此preferredStatusBarStyle,在导航控制器中的 VC 中实现将什么也不做——它们永远不会被调用。

The trick is what the UINavigationControlleruses to decide what to return for UIStatusBarStyleDefaultor UIStatusBarStyleLightContent. It bases this on its UINavigationBar.barStyle. The default (UIBarStyleDefault) results in the dark foreground UIStatusBarStyleDefaultstatus bar. And UIBarStyleBlackwill give a UIStatusBarStyleLightContentstatus bar.

诀窍是用什么UINavigationController来决定返回什么UIStatusBarStyleDefaultUIStatusBarStyleLightContent。它基于其UINavigationBar.barStyle. 默认 ( UIBarStyleDefault) 导致前景UIStatusBarStyleDefault状态栏变暗。并且UIBarStyleBlack会给出一个UIStatusBarStyleLightContent状态栏。

TL;DR:

特尔;博士:

If you want UIStatusBarStyleLightContenton a UINavigationControlleruse:

如果你想UIStatusBarStyleLightContentUINavigationController使用:

self.navigationController.navigationBar.barStyle = UIBarStyleBlack;

回答by serenn

So I actually added a category to UINavigationController but used the methods:

所以我实际上向 UINavigationController 添加了一个类别,但使用了以下方法:

-(UIViewController *)childViewControllerForStatusBarStyle;
-(UIViewController *)childViewControllerForStatusBarHidden;

and had those return the current visible UIViewController. That lets the current visible view controller set its own preferred style/visibility.

并让那些返回当前可见的 UIViewController。这让当前可见视图控制器设置自己的首选样式/可见性。

Here's a complete code snippet for it:

这是它的完整代码片段:

In Swift:

在斯威夫特:

extension UINavigationController {

    public override func childViewControllerForStatusBarHidden() -> UIViewController? {
        return self.topViewController
    }

    public override func childViewControllerForStatusBarStyle() -> UIViewController? {
        return self.topViewController
    }
}

In Objective-C:

在 Objective-C 中:

@interface UINavigationController (StatusBarStyle)

@end

@implementation UINavigationController (StatusBarStyle)

-(UIViewController *)childViewControllerForStatusBarStyle {
    return self.topViewController;
}

-(UIViewController *)childViewControllerForStatusBarHidden {
    return self.topViewController;
}

@end

And for good measure, here's how it's implemented then in a UIViewController:

为了更好的衡量,以下是它在 UIViewController 中的实现方式:

In Swift

在斯威夫特

override public func preferredStatusBarStyle() -> UIStatusBarStyle {
    return .LightContent
}

override func prefersStatusBarHidden() -> Bool {
    return false
}

In Objective-C

在 Objective-C 中

-(UIStatusBarStyle)preferredStatusBarStyle {
    return UIStatusBarStyleLightContent; // your own style
}

- (BOOL)prefersStatusBarHidden {
    return NO; // your own visibility code
}

Finally, make sure your app plist does NOThave the "View controller-based status bar appearance" set to NO. Either delete that line or set it to YES (which I believe is the default now for iOS 7?)

确保最后,让您的应用程序plist中具有“查看基于控制器的状态栏外观”设置为NO。删除该行或将其设置为 YES(我认为这是 iOS 7 现在的默认设置?)

回答by Alex Brown

For anyone still struggling with this, this simple extension in swift should fix the problem for you.

对于仍在为此苦苦挣扎的任何人,swift 中的这个简单扩展应该可以为您解决问题。

extension UINavigationController {
    override open var childForStatusBarStyle: UIViewController? {
        return self.topViewController
    }
}

回答by Luis

My app used all three: UINavigationController, UISplitViewController, UITabBarController, thus these all seem to take control over the status bar and will cause preferedStatusBarStyleto not be called for their children. To override this behavior you can create an extension like the rest of the answers have mentioned. Here is an extension for all three, in Swift 4. Wish Apple was more clear about this sort of stuff.

我的应用程序使用了所有三个: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
    }
}

Edit: Update for Swift 4.2 API changes

编辑:更新 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
    }
}

回答by Yogesh Suthar

Tyson'sanswer is correct for changing the status bar color to white in UINavigationController.

Tyson 的答案对于将状态栏颜色更改为白色是正确的UINavigationController

If anyone want's to accomplish the same result by writing the code in AppDelegatethen use below code and write it inside AppDelegate'sdidFinishLaunchingWithOptionsmethod.

如果有人想通过编写代码来完成相同的结果,AppDelegate则使用下面的代码并将其写入AppDelegate'sdidFinishLaunchingWithOptions方法中。

And don't forget to set the UIViewControllerBasedStatusBarAppearanceto YESin the .plist file, else the change will not reflect.

并且不要忘记在 .plist 文件中设置UIViewControllerBasedStatusBarAppearanceto YES,否则更改不会反映。

Code

代码

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
     // status bar appearance code
     [[UINavigationBar appearance] setBarStyle:UIBarStyleBlack];

     return YES;
}

回答by frin

In addition to serenn's answer, if you are presenting a view controller with a modalPresentationStyle(for example .overCurrentContext), you should also call this on the newly presented view controller:

除了 serenn 的回答之外,如果您使用modalPresentationStyle(例如.overCurrentContext)呈现视图控制器,您还应该在新呈现的视图控制器上调用它:

presentedViewController.modalPresentationCapturesStatusBarAppearance = true

Don't forget to also override the preferredStatusBarStylein the presented view controller.

不要忘记还覆盖preferredStatusBarStyle呈现的视图控制器中的 。

回答by C?ur

On a UINavigationController, preferredStatusBarStyleis not called because its topViewControlleris preferred to self. So, to get preferredStatusBarStylecalled on an UINavigationController, you need to change its childViewControllerForStatusBarStyle.

在 UINavigationController 上,preferredStatusBarStyle不会被调用,因为它topViewControllerself. 因此,要preferredStatusBarStyle调用 UINavigationController,您需要更改其childViewControllerForStatusBarStyle.

Recommendation

推荐

Override your UINavigationController in your class:

在您的班级中覆盖您的 UINavigationController:

class MyRootNavigationController: UINavigationController {
    override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }
    override var childViewControllerForStatusBarStyle: UIViewController? {
        return nil
    }
}

Non recommended alternative

不推荐的替代品

To do it for all UINavigationController, you could override in an extension (warning: it affects UIDocumentPickerViewController, UIImagePickerController, etc.), but you should probably not do it according to Swift documentation:

要为所有 UINavigationController 执行此操作,您可以在扩展中进行覆盖(警告:它会影响 UIDocumentPickerViewController、UIImagePickerController 等),但根据 Swift 文档您可能不应该这样做

extension UINavigationController {
    open override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }
    open override var childViewControllerForStatusBarStyle: UIViewController? {
        return nil
    }
}

回答by Artem Abramov

An addition to Hippo's answer: if you're using a UINavigationController, then it's probably better to add a category:

河马答案的补充:如果您使用的是 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

That solution is probably better than switching to soon-to-be deprecated behaviour.

该解决方案可能比切换到即将弃用的行为更好。

回答by abhimanyu jindal

Swift 4.2 and above

Swift 4.2 及以上

As mentioned in selected answer, root cause is to check your window root view controller object.

所选答案中所述,根本原因是检查您的窗口根视图控制器对象。

Possible cases of your flow structure

流程结构的可能案例

  • Custom UIViewController object is window root view controller

    Your window root view controller is a UIViewController object and it further adds or removes navigation controller or tabController based on your application flow.

    This kind of flow is usually used if your app has pre login flow on navigation stack without tabs and post login flow with tabs and possibly every tab further holds navigation controller.

  • TabBarController object is window root view controller

    This is the flow where window root view controller is tabBarController possibly every tab further holds navigation controller.

  • NavigationController object is window root view controller

    This is the flow where window root view controller is navigationController.

    I am not sure if there is any possibility to add tab bar controller or new navigation controller in an existing navigation controller. But if there is such case, we need to pass the status bar style control to the next container. So, I added the same check in UINavigationController extension to find childForStatusBarStyle

  • 自定义 UIViewController 对象是窗口根视图控制器

    您的窗口根视图控制器是一个 UIViewController 对象,它会根据您的应用程序流程进一步添加或删除导航控制器或 tabController。

    如果您的应用程序在没有选项卡的导航堆栈上具有登录前流程和带选项卡的登录后流程,并且可能每个选项卡进一步包含导航控制器,则通常使用这种流程。

  • TabBarController 对象是窗口根视图控制器

    这是窗口根视图控制器是 tabBarController 的流程,可能每个选项卡都进一步包含导航控制器。

  • NavigationController 对象是窗口根视图控制器

    这是窗口根视图控制器是 navigationController 的流程。

    我不确定是否有可能在现有导航控制器中添加标签栏控制器或新导航控制器。但是如果有这种情况,我们需要将状态栏样式控件传递给下一个容器。所以,我在 UINavigationController 扩展中添加了相同的检查来查找childForStatusBarStyle

Use following extensions, it handles all above scenarios-

使用以下扩展,它处理上述所有场景-

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 { ##代码##.childForStatusBarStyle != nil }?.childForStatusBarStyle?.preferredStatusBarStyle ?? .default
    }
}
  • You don't need UIViewControllerBasedStatusBarAppearancekey in info.plistas it true by default
  • 您不需要UIViewControllerBasedStatusBarAppearance键入,info.plist因为默认情况下为 true

Points to consider for more complex flows

对于更复杂的流程要考虑的要点

  • In case you present new flow modally, it detaches from the existing status bar style flow. So, suppose you are presenting a NewFlowUIViewControllerand then add new navigation or tabBar controller to NewFlowUIViewController, then add extension of NewFlowUIViewControlleras well to manage further view controller's status bar style.

  • In case you set modalPresentationStyleother than fullScreenwhile presenting modally, you must set modalPresentationCapturesStatusBarAppearanceto true so that presented view controller must receive status bar appearance control.

  • 如果您以模态方式呈现新流程,它将与现有状态栏样式流程分离。因此,假设您正在展示一个NewFlowUIViewController,然后将新的导航或 tabBar 控制器NewFlowUIViewController添加到,然后添加扩展名NewFlowUIViewController以进一步管理视图控制器的状态栏样式。

  • 如果您设置modalPresentationStyle而不是fullScreen在模态呈现时,您必须设置modalPresentationCapturesStatusBarAppearance为 true 以便呈现的视图控制器必须接收状态栏外观控制。