适当的方法来隐藏iOS上的状态栏,animation和调整根视图的大小

考虑一个视图控制器,当单击一个button时需要滑出(或隐藏)状态栏。

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

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

我所期望的是扩展状态栏以前使用的空间(animation,与状态栏animation持续时间相同)的根视图。

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

(我知道有很多类似的问题,但我找不到隐藏状态栏的需求,而不是隐藏它来显示一个新的视图控制器)

“蛮力”的做法

显然,下面的作品…

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

…但有缺点:

  • 硬编码幻灯片animation的持续时间
  • 硬编码状态栏的高度
  • 根查看原点保持在(0,-20)。 我喜欢我的框架尽可能从(0,0)开始。

我已经试过了

  • 确保根视图的autoresize掩码具有UIViewAutoresizingFlexibleTopMarginUIViewAutoresizingFlexibleHeight
  • 隐藏状态栏后调用[self.view setNeedsLayout]
  • 隐藏状态栏后调用[self.view setNeedsDisplay]
  • 在隐藏状态栏之前和之后将wantsFullScreenLayout设置为YES

这工作正常,并没有硬编码

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

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

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

然后,在你的button点击方法:

 - (void) buttonClick:(id)sender { // Switch BOOL value self.statusBarHidden = (self.statusBarHidden) ? NO : YES; // Update the status bar [UIView animateWithDuration:0.25 animations:^{ [self setNeedsStatusBarAppearanceUpdate]; }]; } 

要设置animation风格,可以使用下面的命令:

 -(UIStatusBarAnimation)preferredStatusBarUpdateAnimation { return UIStatusBarAnimationSlide; } 

并自定义样式:

 - (UIStatusBarStyle)preferredStatusBarStyle { return UIStatusBarStyleLightContent; } 

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

 - (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”方法中使用了这个代码进行横向取向,一切正常。 但是我不知道它是否会与animation一起工作。

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

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

调用方法(message):

  if ([[UIApplication sharedApplication] isStatusBarHidden]) { [self statusBar:NO]; } else { [self statusBar:YES]; } 

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

花了几个小时的实验和寻找答案后, 特别是这个答案 。 稍微调整一下,我已经成功地做到了,现在最大的差距20px在转换之间已经消失了!

假设我们有一个BOOL isStatusBarEnabled伊娃,这将表明我们是否应该有隐藏状态栏(例如:当访问NSUserDefault检查boolValueForKey )。

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

  • 当显示状态时要修正20px – 但导航没有正确下推,只需添加20点到origin.yself.navgigationController.navigationBar.frame

  • 当我们想要隐藏状态栏的时候做同样的事情,只要origin.y 20个点删除到origin.yself.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]; } } // ... 

…然后,在我的情况下,我有一个设置键,让用户select切换显示/隐藏状态栏。

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

而已!