33

考虑一个在单击按钮时需要滑出(或隐藏)状态栏的视图控制器。

- (void) buttonClick:(id)sender
{
    [[UIApplication sharedApplication] setStatusBarHidden:YES
                                            withAnimation:UIStatusBarAnimationSlide];
}

以上有效地隐藏了状态栏,但没有适当调整根视图的大小,在顶部留下 20 像素的间隙。

我期望的是根视图扩展状态栏先前使用的空间(动画,与状态栏动画具有相同的持续时间)。

这样做的正确方法是什么?

(我知道有很多类似的问题,但我找不到任何关于按需隐藏状态栏而不是隐藏它以显示新视图控制器的信息)

“蛮力”方法

显然,以下工作......

[[UIApplication sharedApplication] setStatusBarHidden:YES
                                        withAnimation:UIStatusBarAnimationSlide];
[UIView animateWithDuration:0.25 animations:^{
    CGRect frame = self.view.frame;
    frame.origin.y -= 20;
    frame.size.height += 20;
    self.view.frame = frame;
}];

...但有缺点:

  • 硬编码幻灯片动画的持续时间
  • 硬编码状态栏的高度
  • 根视图原点保持在 (0,-20)。我喜欢我的帧尽可能从 (0,0) 开始。

我已经尝试过的

  • 确保根视图的自动调整大小掩码具有UIViewAutoresizingFlexibleTopMarginUIViewAutoresizingFlexibleHeight.
  • [self.view setNeedsLayout]隐藏状态栏后调用。
  • [self.view setNeedsDisplay]隐藏状态栏后调用。
  • 设置wantsFullScreenLayoutYES隐藏状态栏前后。
4

7 回答 7

27

对于那些尝试使用基于视图控制器的状态栏外观来实现这一点的人,您需要在视图控制器中实现 prefersStatusBarHidden 方法

 - (BOOL)prefersStatusBarHidden
{
    // If self.statusBarHidden is TRUE, return YES. If FALSE, return NO.
    return (self.statusBarHidden) ? YES : NO;
}

然后,在您的按钮单击方法中:

- (void) buttonClick:(id)sender
{
    // Switch BOOL value
    self.statusBarHidden = (self.statusBarHidden) ? NO : YES;

    // Update the status bar
    [UIView animateWithDuration:0.25 animations:^{
        [self setNeedsStatusBarAppearanceUpdate];
    }];
}

要设置动画样式,请使用:

-(UIStatusBarAnimation)preferredStatusBarUpdateAnimation
{
    return UIStatusBarAnimationSlide;
}

并自定义样式:

- (UIStatusBarStyle)preferredStatusBarStyle
{
    return UIStatusBarStyleLightContent;
}
于 2015-11-14T23:14:53.627 回答
15

这工作正常,没有硬编码

CGRect appFrame = [[UIScreen mainScreen] applicationFrame];

[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
[UIView animateWithDuration:0.25 animations:^{
    self.navigationController.navigationBar.frame = self.navigationController.navigationBar.bounds;
    self.view.window.frame = CGRectMake(0, 0, appFrame.size.width, appFrame.size.height);
}];
于 2012-11-29T13:05:15.013 回答
8

您可以呈现然后关闭模式视图控制器以正确隐藏状态栏

- (void)toggleStatusBar {
    BOOL isStatusBarHidden = [[UIApplication sharedApplication] isStatusBarHidden];
    [[UIApplication sharedApplication] setStatusBarHidden:!isStatusBarHidden];

    UIViewController *vc = [[UIViewController alloc] init];
    [self presentViewController:vc animated:NO completion:nil];
    [self dismissViewControllerAnimated:NO completion:nil];
    [vc release];
}

我在横向的“willAnimateRotationToInterfaceOrientation”方法中使用了这段代码,一切正常。但我不知道它是否适用于动画。

于 2013-05-23T09:16:49.597 回答
7

隐藏或显示也会重新调整视图大小的状态栏:

-(void)statusBar:(BOOL)status {
UIViewController *rootViewController = self.view.window.rootViewController;
UIView *view = rootViewController.view;

// Hide/Unhide the status bar
[[UIApplication sharedApplication] setStatusBarHidden:status]; // BOOL : YES or NO

// statusBar frame
CGRect statusBarFrame = [UIApplication.sharedApplication statusBarFrame];
// Establish baseline frame
CGRect newViewFrame = self.view.window.bounds;

// Check statusBar frame is worth dodging
if (!CGRectEqualToRect(statusBarFrame, CGRectZero)) {
    UIInterfaceOrientation currentOrientation = rootViewController.interfaceOrientation;
    if (UIInterfaceOrientationIsPortrait(currentOrientation)) {
        // If portrait need to shrink height
        newViewFrame.size.height -= statusBarFrame.size.height;
        if (currentOrientation == UIInterfaceOrientationPortrait) {
            // If not upside-down move down origin
            newViewFrame.origin.y += statusBarFrame.size.height;
        }
    } else { // Is landscape 
        // portrait shrink width
        newViewFrame.size.width -= statusBarFrame.size.width;
        if (currentOrientation == UIInterfaceOrientationLandscapeLeft) {
            // If the status bar is on the left side of the window move origin
            newViewFrame.origin.x += statusBarFrame.size.width;
        }
    }
}
view.frame = newViewFrame; // pass new frame 
}

调用方法(消息):

 if ([[UIApplication sharedApplication] isStatusBarHidden]) {
        [self statusBar:NO];
 } else {
        [self statusBar:YES];
 }
于 2013-04-30T15:46:42.500 回答
4

为方便起见,@awfulcode 答案的 Swift 4 变体:

var statusBarHidden = false {
    didSet {
        UIView.animate(withDuration: 0.25) {
            self.setNeedsStatusBarAppearanceUpdate()
        }
    }
}

override var preferredStatusBarStyle: UIStatusBarStyle {
    return .default
}

override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation {
    return .fade
}

override var prefersStatusBarHidden: Bool {
    return statusBarHidden
}
于 2018-06-16T22:55:07.100 回答
0

我知道这样做的方法,但缺点也很明显。您可以self.wantsFullScreenLayout = YES;在您的viewDidLoad和设置您的 xib 文件与屏幕一样大(320x480 和 iPhone5 的 320x568)。但这意味着状态栏下方的区域也是不可见的。并且使用这种方式,当您隐藏状态栏时,您的视图也不会展开。如果您没有在状态栏区域显示的内容,您可以考虑这种方式。

于 2012-11-29T12:00:34.793 回答
0

经过数小时的实验和寻找答案;特别是这个答案。稍作调整,我成功地做到了,现在过渡之间的顶部间隙 20px 消失了!

假设我们有一个 BOOL isStatusBarEnabledivar,它将指示我们是否应该隐藏状态栏(例如:访问NSUserDefault检查时boolValueForKey)。

所以,我们首先通过 来检查 statusBar 是否已经被隐藏[[UIApplication sharedApplication] isStatusBarHidden],如果它没有被隐藏(== 被显示),我们就隐藏它!否则,另当别论!

  • 要在显示状态时修复 20px - 但导航未正确下推,只需将 20 点添加origin.yself.navgigationController.navigationBar.frame.

  • 当我们想要隐藏状态栏时也这样做,只需删除那个 20 点就可以origin.y了。self.navgigationController.navigationBar.frame0

就是这个!

@implementation SomeViewController {
    BOOL isStatusBarEnabled;
}

// ...

- (void)toggleStatusBar
{
    UINavigationBar *navBar = self.navigationController.navigationBar;

    if ([[UIApplication sharedApplication] isStatusBarHidden]) {

        // Change to regular mode
        // Show status bar
        [[UIApplication sharedApplication] setStatusBarHidden:NO
                                                withAnimation:UIStatusBarAnimationSlide];
        [UIView animateWithDuration:0.3
                         animations:^{
                             navBar.frame = CGRectMake(navBar.frame.origin.x, 20, navBar.frame.size.width, navBar.frame.size.height);
                         } completion:nil];

    } else if (![[UIApplication sharedApplication] isStatusBarHidden]) {
        // Change to fullscreen mode
        // Hide status bar
        [[UIApplication sharedApplication] setStatusBarHidden:YES
                                                withAnimation:UIStatusBarAnimationSlide];
        [UIView animateWithDuration:0.4
                         animations:^{
                             navBar.frame = CGRectMake(navBar.frame.origin.x, 0, navBar.frame.size.width, navBar.frame.size.height);
                         } completion:nil];
    }

}

// ...

...然后,就我而言,我有一个设置键让用户选择切换显示/隐藏状态栏。

// ...

- (void)onDefaultsChanged:(NSNotification*)aNotification
{

    NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
    isStatusBarEnabled = [standardDefaults boolForKey:kStatusBar];

    if (isStatusBarEnabled) {

      if ([[UIApplication sharedApplication] isStatusBarHidden]) {

          // Change to regular mode
          // Show status bar
          [self toggleStatusBar];   

    } else {

        // Change to fullscreen mode
        // Hide status bar
        [self toggleStatusBar];

  }

  // ...
}

就是这样!

于 2013-05-03T18:16:16.503 回答