How to prevent status bar from overlapping content with hidesBarsOnSwipe set on UINavigationController?
Solution 1
Building off of anas' answer, I have a working solution (I'm assuming tableViewController
is your UITableViewController
instance):
In a UINavigationController
subclass (or also potentially from tableViewController
):
- (void)viewDidLoad {
if ([self respondsToSelector:@selector(barHideOnSwipeGestureRecognizer)]) {
// iOS 8+
self.hidesBarsOnSwipe = YES;
[self.barHideOnSwipeGestureRecognizer addTarget:self action:@selector(swipe:)];
}
}
- (void)swipe:(UISwipeGestureRecognizer *)recognizer {
BOOL shouldHideStatusBar = self.navigationController.navigationBar.frame.origin.y < 0;
tableViewController.hideStatusBar = shouldHideStatusBar;
[UIView animateWithDuration:0.2 animations:^{
[tableViewController setNeedsStatusBarAppearanceUpdate];
}];
}
In your tableViewController
:
@property(nonatomic, getter = shouldHideStatusBar) BOOL hideStatusBar;
- (BOOL)prefersStatusBarHidden {
return [self shouldHideStatusBar];
}
Let me know if this doesn't work for you. A few non-obvious things:
-
self.navigationController.navigationBar.frame.origin.y
was -44 (the negative height of the navigation bar) when hidden, and 20 (the height of the status bar) when visible. There was no in-between, even during animations, so a negative value == hidden and a nonnegative value == visible. - The child view controller is the one queried for whether or not the status bar should be hidden. In my case, I have a
UIViewController
within aUINavigationController
within aUITabBarController
, and it didn't work until I overrodeprefersStatusBarHidden
on theUIViewController
. - Since a hidden status bar has no frame, your content might jerk upwards 20 points unless you wrap the call to
setNeedsStatusBarAppearanceUpdate
in an animation block. - Hopefully the syntax is correct; I backported this from my Swift code.
Solution 2
Actually it is pretty easy to do. You just need to connect navigation isNavigationBarHidden property with status bar.
Objective-C
- (BOOL)prefersStatusBarHidden {
return self.navigationController.isNavigationBarHidden;
}
Swift <= 2.3
override func prefersStatusBarHidden() -> Bool {
return navigationController?.navigationBarHidden ?? false
}
Swift 3.0
override var prefersStatusBarHidden: Bool {
return navigationController?.isNavigationBarHidden ?? false
}
And be sure you have "View controller-based status bar appearance" = "YES" in your application .plist file.
Solution 3
That new property comes with its barHideOnSwipeGestureRecognizer
.
From the UINavigationController Class Reference:
You can make changes to the gesture recognizer as needed but must not change its delegate and you must not remove the default target object and action that come configured with it. Do not try to replace this gesture recognizer by overriding the property.
But you can add a target:
[self.navigationController setHidesBarsOnSwipe:YES];
[self.navigationController.barHideOnSwipeGestureRecognizer addTarget:self action:@selector(swipeGesture:)];
... and do whatever you want in the callback:
- (void)swipeGesture:(UIPanGestureRecognizer*)gesture
{
// Tweak the status bar
}
You might have to manually switch on the gesture states, figure out when to hide/show the status bar, etc. Hope that helps!
Solution 4
The answer from @iOSergey works perfect!
Here is the solution in Swift 1.2. Add the following code to the views .swift file:
override func prefersStatusBarHidden() -> Bool {
return self.navigationController!.navigationBarHidden as Bool
}
Solution 5
If you want to hide status bar with animation:
override func preferredStatusBarUpdateAnimation() -> UIStatusBarAnimation {
return .Slide
}
override func prefersStatusBarHidden() -> Bool {
return navigationController?.navigationBarHidden ?? false
}
Comments
-
Michał Ciuba over 3 years
I'm trying to use the new feature added in iOS 8 - hiding the navigation bar while user is scrolling the table view (similar to what mobile Safari does). I'm setting the property
hidesBarsOnSwipe
ofUINavigationController
toYES
inviewDidAppear
method ofUITableViewController
:- (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; if([self.navigationController respondsToSelector:@selector(hidesBarsOnSwipe)]) { self.navigationController.hidesBarsOnSwipe = YES; } }
The navigation bar hides when the view is being scrolled. So far so good. But the status bar is still visible and my table view contents show through it, which looks ugly:
I tried setting
edgesForExtendedLayout
toUIEdgeRectNone
or adjusting thecontentInset
of the table view, but it didn't help. Is there any other solution to hide the status bar along with the navigation bar, or make it opaque?