可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.
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.
What I already tried
- Made sure the autoresize mask of the root view has
UIViewAutoresizingFlexibleTopMargin
and UIViewAutoresizingFlexibleHeight
.
- Called
[self.view setNeedsLayout]
after hiding the status bar.
- Called
[self.view setNeedsDisplay]
after hiding the status bar.
- Set
wantsFullScreenLayout
to YES
before and after hiding the status bar.
回答1:
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);
}];
回答2:
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
- (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;
}
回答3:
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.
回答4:
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];
}
回答5:
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.
回答6:
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!
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
).
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!
To fix 20px when status is shown - but navigation is not properly pushed down, just add 20 point to origin.y
of self.navgigationController.navigationBar.frame
.
Do the same when we want to hide status bar, just remove that 20 point to origin.y
of self.navgigationController.navigationBar.frame
so just leave it 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!
回答7:
For convenience, a Swift 4 variant of @awfulcode's answer:
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
}