【问题标题】:UIViewController's prefersStatusBarHidden not workingUIViewController 的 prefersStatusBarHidden 不起作用
【发布时间】:2014-06-30 04:56:48
【问题描述】:

我正在尝试隐藏我的一个视图控制器的状态栏(当模态显示时)。当我展示视图控制器时,状态栏将被隐藏,然后在关闭时返回。

我已将以下代码添加到呈现的视图控制器中

- (BOOL)prefersStatusBarHidden
{
    return YES;
}

我还将 Info.plist 文件中的键设置为以下内容:

<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>

据我了解,这应该是完成这项工作所需的全部内容。

我还使用自定义动画控制器来进行符合UIViewControllerAnimatedTransitioning 协议的演示。在animateTransition: 实现中,我尝试手动调用prefersStatusBarHidden,然后是setNeedsStatusBarAppearanceUpdate 以确保正在调用,但状态栏仍然存在。

任何想法为什么会发生这种情况将不胜感激。我已经搜索过 StackOverflow,但似乎没有人遇到过这个问题,所有接受的答案都是指调用 setNeedsStatusBarAppearanceUpdate,我已经在这样做了。

EDIT - 下面的代码现在似乎 WORK 符合需要

- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
{
    if (self.isPresenting) {
        UIView *containerView = [transitionContext containerView];

        UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
        UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

        toViewController.view.frame = containerView.frame;

        [containerView addSubview:toViewController.view];

        // Ask the presented controller whether to display the status bar
        [toViewController setNeedsStatusBarAppearanceUpdate];

        [UIView animateWithDuration:1.0f delay:0.0f options:UIViewAnimationOptionCurveEaseIn animations:^{
            toViewController.view.alpha = 1.0f;
            fromViewController.view.alpha = 0.0f;
        } completion:^(BOOL finished) {
            [transitionContext completeTransition:YES];
        }];
    }
    else {
        // do the reverse
        UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
        UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

        [UIView animateWithDuration:1.0f delay:0.0f options:UIViewAnimationOptionCurveEaseIn animations:^{
            toViewController.view.alpha = 1.0f;
            fromViewController.view.alpha = 0.0f;
        } completion:^(BOOL finished) {
            [transitionContext completeTransition:YES];
            // Once dismissed - ask the presenting controller if the status bar should be presented
            [toViewController setNeedsStatusBarAppearanceUpdate];
        }];
    }
}

....

// PresentingController.m
- (BOOL)prefersStatusBarHidden
{
    if (self.presentedViewController) {
        return YES;
    }
    return NO;
}

// PresentedController.m
- (BOOL)prefersStatusBarHidden
{
    return YES;
}

【问题讨论】:

  • 在 prefersStatusBarHidden 中添加一个断点来检查它是否被调用。
  • 肯定是被调用了,断点被命中了。
  • 您是否尝试删除密钥?因为他们不应该被需要。
  • 是的,我试过了。有趣的是,我刚刚尝试展示没有自定义转换控制器(iOS 原生模式)的控制器,它似乎删除了状态栏。但我需要让它与这个自定义动画控制器一起工作。
  • 嗯,也许可以贴一些代码自定义动画是如何工作的?

标签: ios objective-c ios7 uiviewcontroller ios7-statusbar


【解决方案1】:

在 iOS7 中,实际上有一个 UIViewController 的新属性,称为 modalPresentationCapturesStatusBarAppearanceApple iOS reference.

默认值为 NO。

当您通过调用 presentViewController:animated:completion: 方法呈现视图控制器时,仅当呈现控制器的 modalPresentationStyle 值为 UIModalPresentationFullScreen 时,状态栏外观控制才会从呈现转移到呈现的视图控制器。通过将此属性设置为 YES,您可以指定呈现的视图控制器控件状态栏的外观,即使呈现非全屏。

对于全屏显示的视图控制器,系统会忽略此属性的值。

因此,对于普通全屏以外的任何presentationStyle(例如:UIModalPresentationCustom),如果你想捕获状态栏,这个必须设置。要使用,您只需在正在呈现的视图控制器上将其设置为 YES

toVC.modalPresentationCapturesStatusBarAppearance = YES;

【讨论】:

  • 刚刚注意到,如果模态演示样式为“当前上下文”,则此方法不起作用 toVC.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
  • 它也适用于 UIModalPresentationStyle.OverCurrentContext
  • 我很生气,直到我找到了这个提示 :-)))
  • 谢谢,在iOS8中使用presentationStype = .overCurrentContext是我的问题。我花了 2 个小时寻找解决方案。在 iOS9+ 中,我不必再将此 modalPresentationCapturesStatusBarAppearance 设置为 true。
  • 你拯救了我的一天,我在 Google BottomSheet 中使用它,它工作正常。你需要把它和prefersStatusBarHidden = true结合起来
【解决方案2】:

我会猜测(受过教育,但仍然是猜测)这是因为当您使用自定义转换执行呈现的视图控制器时,在 iOS 7 中,旧的视图控制器仍然存在。因此它可能仍然有发言权。

你甚至可以在 its prefersStatusBarHidden 中放置一个断点来查看;如果没有实施,您将不得不实施它。默认值为 NO,因此如果咨询,这将解释您的结果。

如果我是对的,您需要实现 old 视图控制器的 prefersStatusBarHidden 以给出两个不同的答案,具体取决于它是否具有 presentedViewController

编辑我现在已经确认了这一点。比我想象的还要糟糕;在我的测试中,第二个视图控制器的 prefersStatusBarHidden 根本没有被调用。整个事情都在第一个视图控制器的手中。这是有道理的,因为正如我所说,第一个视图控制器永远不会消失。对于自定义演示动画,第二个视图控制器从属于第一个视图控制器,因为第二个视图可以部分悬停在第一个视图上。

因此,您将不得不完全从第一个视图控制器驱动状态栏。您可以通过调用[self setNeedsStatusBarAppearanceUpdate] 来调用它的prefersStatusBarHidden。您需要根据具体情况给出不同的答案。这可能有点棘手。这是一个简单的实现,但它可能无法涵盖所有​​情况:

// ViewController1:

-(void)setHide:(NSNumber*)yn {
    self->hide = [yn boolValue]; // a BOOL ivar
    [self setNeedsStatusBarAppearanceUpdate];
}
-(BOOL)prefersStatusBarHidden {
    return self->hide;
}
- (IBAction)doButton:(id)sender {
    self->hide = YES;
    [self setNeedsStatusBarAppearanceUpdate];
    [self presentViewController:[ViewController2 new] animated:YES completion:nil];
}

// ==========

// ViewController2:

- (IBAction)doButton:(id)sender {
    [self.presentingViewController setValue:NO forKey:@"hide"];
    [self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}

【讨论】:

  • 是的,我感觉这也是问题所在。我需要通过控制器层次结构进行检查,因为如果呈现模式,呈现控制器将返回 YES。所以,理论上,它应该可以工作。
  • 感谢@matt,您的 cmets 非常有帮助。我现在已经将问题中的代码编辑为似乎对我有用的东西。我使用的解决方法是在自定义动画期间手动调用控制器 prefersStatusBarHidden 方法。我会接受这个答案,因为它准确地解释了问题。
  • 除了你可以剪掉看起来像这样的线条:[toViewController prefersStatusBarHidden]; - 他们错了,什么也不做。
  • 如果[toViewController prefersStatusBarHidden];调用从dismissal code中移除,则在presentedViewController被dismiss后不会返回状态栏。
  • 我很难理解这是怎么回事。 prefersStatusBarHidden 应该被系统调用。它返回一个 BOOL,你甚至没有捕获它(你只是把它扔掉了);而你在系统背后调用它,所以系统什么也学不到。对setNeedsStatusBarAppearanceUpdate 的调用很重要,因为它会导致系统 调用prefersStatusBarHidden 并因此重新检索其结果。
【解决方案3】:

如果它不起作用并且您的 UIViewController 是 UINavigationController 中的子级,那么此代码可能是您的解决方案。

open override var prefersStatusBarHidden: Bool {
    return topViewController?.prefersStatusBarHidden ?? super.prefersStatusBarHidden
}

基本上 UINavigationController 使用它自己的 prefersStatusBarHidden 值,但在我的情况下,我想通过其顶层视图控制器在层次结构中的属性覆盖它。

【讨论】:

    【解决方案4】:

    您可以将其添加到 info.plist

    “查看基于控制器的状态栏外观”并将值设置为“否”

    【讨论】:

    • 将此属性设置为 YES 并在特定视图控制器中覆盖 prefersStatusBarHidden 确实为我隐藏了仅此视图控制器中的状态栏。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多