在 iOS 上隐藏状态栏的正确方法,带有动画和调整根视图的大小
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13624695/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Proper way to hide status bar on iOS, with animation and resizing root view
提问by hpique
Consider a view controller that needs to slide out (or hide) the status bar when a button is clicked.
考虑一个需要在单击按钮时滑出(或隐藏)状态栏的视图控制器。
- (void) buttonClick:(id)sender
{
[[UIApplication sharedApplication] setStatusBarHidden:YES
withAnimation:UIStatusBarAnimationSlide];
}
The above effectively hides the status bar, but does not resize the root view appropriately, leaving a 20 pixel gap on top.
以上有效地隐藏了状态栏,但没有适当地调整根视图的大小,在顶部留下 20 像素的间隙。
What I expected is the root view to expand over the space that was previously used by the status bar (animated, with the same duration than the status bar animation).
我期望的是根视图扩展到状态栏以前使用的空间(动画,与状态栏动画的持续时间相同)。
What's the proper way of doing this?
这样做的正确方法是什么?
(I'm aware there are plenty of similar questions, but I couldn't find any about hiding the status bar on demand as opposed to hiding it to display a new view controller)
(我知道有很多类似的问题,但我找不到任何关于按需隐藏状态栏而不是隐藏它以显示新的视图控制器的问题)
The "brute force" approach
“蛮力”方法
Obviously, the following works...
显然,以下工作...
[[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;
}];
...but has disadvantages:
...但有缺点:
- Hardcodes the duration of the slide animation
- Hardcodes the height of the status bar
- The root view origin stays at (0,-20). I like my frames to start at (0,0) whenever possible.
- 硬编码幻灯片动画的持续时间
- 硬编码状态栏的高度
- 根视图原点停留在 (0,-20)。我喜欢我的帧尽可能从 (0,0) 开始。
What I already tried
我已经尝试过的
- Made sure the autoresize mask of the root view has
UIViewAutoresizingFlexibleTopMargin
andUIViewAutoresizingFlexibleHeight
. - Called
[self.view setNeedsLayout]
after hiding the status bar. - Called
[self.view setNeedsDisplay]
after hiding the status bar. - Set
wantsFullScreenLayout
toYES
before and after hiding the status bar.
- 确保根视图的自动调整大小掩码具有
UIViewAutoresizingFlexibleTopMargin
和UIViewAutoresizingFlexibleHeight
。 [self.view setNeedsLayout]
隐藏状态栏后调用。[self.view setNeedsDisplay]
隐藏状态栏后调用。- 设置
wantsFullScreenLayout
为YES
隐藏状态栏之前和之后。
采纳答案by Lefteris
This works fine and has nothing hard coded.
这工作正常并且没有任何硬编码。
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);
}];
回答by awfulcode
For those that are trying to implement this with view controller-based status bar appearance, you need to implement the prefersStatusBarHidden method in your view controller
对于那些试图使用基于视图控制器的状态栏外观来实现这一点的人,您需要在视图控制器中实现 prefersStatusBarHidden 方法
- (BOOL)prefersStatusBarHidden
{
// If self.statusBarHidden is TRUE, return YES. If FALSE, return NO.
return (self.statusBarHidden) ? YES : NO;
}
And then, in your button click method:
然后,在您的按钮单击方法中:
- (void) buttonClick:(id)sender
{
// Switch BOOL value
self.statusBarHidden = (self.statusBarHidden) ? NO : YES;
// Update the status bar
[UIView animateWithDuration:0.25 animations:^{
[self setNeedsStatusBarAppearanceUpdate];
}];
}
To set the animation style, you use this:
要设置动画样式,请使用以下命令:
-(UIStatusBarAnimation)preferredStatusBarUpdateAnimation
{
return UIStatusBarAnimationSlide;
}
And to customize the style:
并自定义样式:
- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
回答by Exception
You can present and then dismiss modal view controller to hide status bar correctly
您可以呈现然后关闭模态视图控制器以正确隐藏状态栏
- (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];
}
I used this code in the "willAnimateRotationToInterfaceOrientation" method for landscape orientation and everything is working correctly. But I don't know if it will work with animation.
我在横向方向的“willAnimateRotationToInterfaceOrientation”方法中使用了此代码,并且一切正常。但我不知道它是否适用于动画。
回答by Shams Ahmed
Hide or Show status bar that also re-sizes the view:
隐藏或显示也会重新调整视图大小的状态栏:
-(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
}
call method(message):
调用方法(消息):
if ([[UIApplication sharedApplication] isStatusBarHidden]) {
[self statusBar:NO];
} else {
[self statusBar:YES];
}
回答by pinch
For convenience, a Swift 4 variant of @awfulcode's answer:
为方便起见,@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
}
回答by Vinh Nguyen
After spending hours of experiment and searching for answer; particularly this answer. With a bit tweaking, I have successfully make it, now the top gap 20px is gone between transition!
经过数小时的实验和寻找答案;特别是这个答案。稍微调整一下,我已经成功做到了,现在过渡之间的顶部间隙 20px 消失了!
Suppose we have a BOOL isStatusBarEnabled
ivar that will indicate whether we should have status bar hidden or not, (eg: when accessing NSUserDefault
for checking boolValueForKey
).
假设我们有一个 BOOL isStatusBarEnabled
ivar,它将指示我们是否应该隐藏状态栏,(例如:访问NSUserDefault
检查时boolValueForKey
)。
So, we first check for whether if statusBar is already hidden or not via [[UIApplication sharedApplication] isStatusBarHidden]
, if it is not hidden (== being shown), we hide it! Else, do otherwise!
所以,我们首先通过检查 statusBar 是否已经隐藏[[UIApplication sharedApplication] isStatusBarHidden]
,如果它没有隐藏(== 被显示),我们隐藏它!否则,做其他事情!
To fix 20px when status is shown - but navigation is not properly pushed down, just add 20 point to
origin.y
ofself.navgigationController.navigationBar.frame
.Do the same when we want to hide status bar, just remove that 20 point to
origin.y
ofself.navgigationController.navigationBar.frame
so just leave it0
.
要在显示状态时修复 20px - 但导航未正确按下,只需将 20 点添加到
origin.y
ofself.navgigationController.navigationBar.frame
。做同样的,当我们想隐藏状态栏,只是删除20点
origin.y
的self.navgigationController.navigationBar.frame
这么这么走它0
。
this is it!
就是这个!
@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];
}
}
// ...
... then, in my case, I have a setting key to let user choose toggle show/hide status bar.
...然后,就我而言,我有一个设置键让用户选择切换显示/隐藏状态栏。
// ...
- (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];
}
// ...
}
that's it!
就是这样!
回答by sunkehappy
I know a walk around way for this but the disadvantages is also obvious. You can set self.wantsFullScreenLayout = YES;
in your viewDidLoad
and set your xib file as big as the screen(320x480, and 320x568 for iPhone5). But this means that the area under the status bar is also not visible. And using this way your view will also not expand when you hide the status bar. You can consider this way if you don't have something to display in status bar area.
我知道为此四处走动,但缺点也很明显。您可以设置self.wantsFullScreenLayout = YES;
在viewDidLoad
与设置您的XIB文件一样大的屏幕(分辨率320x480,和320x568的iPhone5的)。但这意味着状态栏下方的区域也是不可见的。使用这种方式,当您隐藏状态栏时,您的视图也不会扩展。如果状态栏区域没有要显示的内容,可以考虑这种方式。