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

Iphone 在iOS上隐藏状态栏的正确方法,包括动画和调整根视图的大小,iphone,ios,uiviewcontroller,statusbar,uistatusbar,Iphone,Ios,Uiviewcontroller,Statusbar,Uistatusbar,考虑一个视图控制器,它需要在单击按钮时滑出(或隐藏)状态栏 - (void) buttonClick:(id)sender { [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide]; } 上面的内容有效地隐藏了状态栏,但没有适当地调整根视图的大小,在顶部留下

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

- (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)开始
我已经试过了
  • 确保根视图的自动调整大小掩码具有
    UIViewAutoresizingFlexibleTopMargin
    UIViewAutoresizingFlexibleHeight
  • 隐藏状态栏后调用了
    [self.view setNeedsLayout]
  • 隐藏状态栏后调用了
    [self.view setNeedsDisplay]
  • 在隐藏状态栏之前和之后,将
    wantsFullScreenLayout
    设置为
    YES

我知道有一种绕道而行的方法,但缺点也是显而易见的。您可以设置
self.wantsFullScreenLayout=YES
在您的
视图中加载
,并将您的xib文件设置为屏幕大小(对于iPhone5为320x480和320x568)。但这意味着状态栏下的区域也不可见。使用这种方式,当您隐藏状态栏时,视图也不会展开。如果在状态栏区域没有显示的东西,你可以考虑这个方法。

< P>这是很好的,没有任何强>硬编码< /强> < /P>
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);
}];

隐藏或显示同时调整视图大小的状态栏:

-(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 
}
调用方法(消息):


在花费数小时的实验和寻找答案之后;尤其通过一点调整,我已经成功地做到了,现在顶部间隙20px在过渡之间消失了

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

因此,我们首先通过
[[UIApplication sharedApplication]isStatusBarHidden]
检查statusBar是否已隐藏,如果它未隐藏(=正在显示),我们将其隐藏!否则,就做别的

  • 要在显示状态时修复20px,但导航未正确按下,只需在
    self.navgigationController.navigationBar.frame的
    origin.y
    中添加20点即可

  • 当我们想隐藏状态栏时,也要这样做,只需删除
    self.navgigationController.navigationBar.frame的
    origin.y
    的20点,所以只需将其保留
    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];
    }

}

// ...
。。。然后,在我的例子中,我有一个设置键,让用户选择切换显示/隐藏状态栏

// ...

- (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];

  }

  // ...
}

就这样

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

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

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

对于那些试图使用基于视图控制器的状态栏外观实现此功能的人,您需要在视图控制器中实现prefersStatusBarHidden方法

-(BOOL)首选StatusBarHidden
{
//如果self.statusBarHidden为TRUE,则返回YES。如果为FALSE,则返回NO。
返回(self.statusBarHidden)?是:否;
}
然后,在按钮单击方法中:

-(无效)按钮单击:(id)发件人
{
//开关布尔值
self.statusBarHidden=(self.statusBarHidden)?否:是;
//更新状态栏
[UIView animateWithDuration:0.25动画:^{
[self-setNeedsStatusBarAppearanceUpdate];
}];
}
要设置动画样式,请使用以下命令:

-(UIStatusBarAnimation)首选状态栏更新映像
{
返回UIStatusBarAnimationSlide;
}
要自定义样式,请执行以下操作:

-(UIStatusBarStyle)首选状态BarStyle
{
返回UIStatusBarStyleLightContent;
}

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

谢谢@Lefteris。我很快就会查出来。但是,它会对动画持续时间进行硬编码。AFAIK,无法获取状态栏动画持续时间。您可以通过订阅键盘willshow/willhide通知来获取键盘动画持续时间,但不能订阅UIStatusBar。此外,iOS中似乎存在一个从未修复的bug,当状态栏隐藏或显示时,UIApplicationIDChangeStatusBarFrameNotification/UIApplicationWillChangeStatusBarFrameNotification不会被触发…嗨。。我有两个选项卡的tabbar应用程序。我只想隐藏第二个选项卡状态栏,但如果我这样做,我的第一个选项卡状态栏也将隐藏。如何修复?@GajendraKChauhan每个窗口只有一个状态栏,这意味着每个应用程序也有一个状态栏。嵌套控制器不起作用。但这是一个很好的方法。它也可以这样做:self.view.window.height+=statusBarHiddenState-20 : 20; (如果控制器管理状态栏)。孩子控制器仍然有问题。太好了。它起作用了。不知道为什么。这似乎是一个简单的黑客攻击。这是一个更好的答案。在iOS 7中不推荐使用WantFullScreenLayout,可能重复推荐和测试的方法。谢谢不要认为
[UIView animateWithDuration…]
在这里有任何价值;至少在iOS 13上运行时不会。
UIStatusBarAnima
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
}