适当的方法来隐藏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掩码具有
UIViewAutoresizingFlexibleTopMargin
和UIViewAutoresizingFlexibleHeight
。 - 隐藏状态栏后调用
[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.y
的self.navgigationController.navigationBar.frame
。 -
当我们想要隐藏状态栏的时候做同样的事情,只要
origin.y
20个点删除到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]; } } // ...
…然后,在我的情况下,我有一个设置键,让用户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]; } // ... }
而已!