I am trying to make the status bar for one of my view controllers to be hidden (when displayed modally). When I'm presenting the view controller, the status bar is is to be hidden and then returned when dismissed.
I have added the following code to the presented view controller
- (BOOL)prefersStatusBarHidden
{
return YES;
}
I have also set the keys in the Info.plist file to the following:
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>
From my understanding this should be all that is required to make this work.
I am also using a custom Animation Controller to do the presenting which conforms to the UIViewControllerAnimatedTransitioning
protocol. In the animateTransition:
implementation I have tried to manually call prefersStatusBarHidden
, followed by setNeedsStatusBarAppearanceUpdate
to ensure the call is being made, but the status bar remains.
Any ideas why this is happening would be appreciated. I have searched StackOverflow, but it appears no one has had this issue, all accepted answers refer to calling setNeedsStatusBarAppearanceUpdate
, which I am already doing.
EDIT - The code below now seems to WORK as desired
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
{
if (self.isPresenting) {
UIView *containerView = [transitionContext containerView];
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
toViewController.view.frame = containerView.frame;
[containerView addSubview:toViewController.view];
// Ask the presented controller whether to display the status bar
[toViewController setNeedsStatusBarAppearanceUpdate];
[UIView animateWithDuration:1.0f delay:0.0f options:UIViewAnimationOptionCurveEaseIn animations:^{
toViewController.view.alpha = 1.0f;
fromViewController.view.alpha = 0.0f;
} completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
}
else {
// do the reverse
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
[UIView animateWithDuration:1.0f delay:0.0f options:UIViewAnimationOptionCurveEaseIn animations:^{
toViewController.view.alpha = 1.0f;
fromViewController.view.alpha = 0.0f;
} completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
// Once dismissed - ask the presenting controller if the status bar should be presented
[toViewController setNeedsStatusBarAppearanceUpdate];
}];
}
}
....
// PresentingController.m
- (BOOL)prefersStatusBarHidden
{
if (self.presentedViewController) {
return YES;
}
return NO;
}
// PresentedController.m
- (BOOL)prefersStatusBarHidden
{
return YES;
}
You may add this to info.plist
"View controller-based status bar appearance" and set the value to "No"
I'm going to guess (educated, but still a guess) that this is because when you do a presented view controller using a custom transition, in iOS 7, the old view controller is still there. Therefore it probably still gets a say.
You might even put a breakpoint in its
prefersStatusBarHidden
to see; you'll have to implement it if it isn't implemented. The default is NO, so if it is consulted, that would explain your result.If I'm right, you would need to implement the old view controller's
prefersStatusBarHidden
to give two different answers, depending on whether it has apresentedViewController
or not.EDIT I've now confirmed this. It's even worse than I thought; in my testing, the second view controller's
prefersStatusBarHidden
isn't being called at all. The whole thing is in the hands of the first view controller. This makes sense because, as I said, the first view controller never goes away; with a custom presentation animation, the second view controller is subordinate to the first one, because the second view can hover partially over the first view.Thus you're going to have to drive the status bar entirely from the first view controller. You can cause its
prefersStatusBarHidden
to be called by calling[self setNeedsStatusBarAppearanceUpdate]
. You'll need to give a different answer depending on the circumstances. This can be a bit tricky. Here's a simple implementation, but it may not cover all the cases:In iOS7, there's actually a new property for UIViewController called
modalPresentationCapturesStatusBarAppearance
. Apple iOS reference.Therefore, for any presentationStyle other than the normal fullscreen (for example: UIModalPresentationCustom), this must be set if you want to capture the status bar. To use, all you have to do is set it to
YES
on the view controller that's being presented: