在iOS上隐藏状态栏的正确方法,包括动画和调整根视图的大小

时间:2012-11-29 11:23:50

标签: iphone ios uiviewcontroller statusbar uistatusbar

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

- (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]
  • 隐藏状态栏之前和之后将wantsFullScreenLayout设置为YES

7 个答案:

答案 0 :(得分:23)

对于那些尝试使用基于视图控制器的状态栏外观实现此功能的人,您需要在视图控制器中实现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;
}

答案 1 :(得分:16)

这很好用,没有硬编码

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);
}];

答案 2 :(得分: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”方法中使用此代码进行横向定位,一切正常。但我不知道它是否适用于动画。

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

答案 4 :(得分:0)

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

答案 5 :(得分:0)

经过数小时的实验并寻找答案;特别是this answer。稍微调整一下,我已经成功实现了它,现在最大的差距20px在转换之间消失了!

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

因此,我们首先通过[[UIApplication sharedApplication] isStatusBarHidden]检查statusBar是否已被隐藏,如果它未被隐藏(==显示),我们隐藏它!否则,不要这样做!

  • 要在显示状态时修复20px - 但未正确按下导航,只需向origin.y的{​​{1}}添加20个点。

  • 如果我们要隐藏状态栏,请执行相同的操作,只需将该点移至self.navgigationController.navigationBar.frame origin.y,然后将其留空self.navgigationController.navigationBar.frame

就是这样!

0

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

@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];
    }

}

// ...

就是这样!

答案 6 :(得分:0)

为方便起见,@ 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
}