I'm having a problem in my app where there is a black bar at the top of app and my whole view gets pushed down 20pts from the top.
Here is a very short sample project that reproduces the bug: https://github.com/sbiermanlytle/iOS-status-bar-bug/tree/master
To reproduce:
How do I get rid of the black bar?
Here's a full explanation of the sample app:
There's a series of 3 view controllers, 1 launches 2, UIViewControllerBasedStatusBarAppearance
is set to YES
, the 1st and 3rd view controllers hide the status bar, and the 2nd one shows it.
Everything displays ok when you launch the 2nd view and 3rd view, but when you dismiss the 3rd view, there is a black bar at the top of the 2nd view that will not go away.
Looks like iOS bug.
I don't know a beautiful way around this but these certainly works:
Change View controller-based status bar appearance
entry in Info.plist to NO
. Add code like this to all of your view controllers (or to common superclass, hope you have one ;) ):
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[UIApplication sharedApplication] setStatusBarHidden:[self prefersStatusBarHidden]];
}
By manually updating frame of failed system view upon causing condition. This may or may not break something outside of test app.
In UIViewController+TheTweak.h
#import <UIKit/UIKit.h>
@interface UIViewController (TheTweak)
- (void)transitionViewForceLayoutTweak;
@end
In UIViewController+TheTweak.m
(mind the FIXME comment)
#import "UIViewController+TheTweak.h"
#import "UIView+TheTweak.h"
@implementation UIViewController (TheTweak)
- (void)transitionViewForceLayoutTweak {
UIViewController *presenting = [self presentingViewController];
if (([self presentedViewController] != nil) && ([self presentingViewController] != nil)) {
if ([self prefersStatusBarHidden]) {
NSUInteger howDeepDownTheStack = 0;
do {
++howDeepDownTheStack;
presenting = [presenting presentingViewController];
} while (presenting != nil);
//FIXME: replace with a reliable way to get window throughout whole app, without assuming it is the 'key' one. depends on your app's specifics
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
[window forceLayoutTransitionViewsToDepth:howDeepDownTheStack];
}
}
}
@end
In UIView+TheTweak.h
#import <UIKit/UIKit.h>
@interface UIView (TheTweak)
- (void)forceLayoutTransitionViewsToDepth:(NSUInteger)depth;
@end
In UIView+TheTweak.m
#import "UIView+TheTweak.h"
@implementation UIView (TheTweak)
- (void)forceLayoutTransitionViewsToDepth:(NSUInteger)depth {
if (depth > 0) { //just in case
for (UIView *childView in [self subviews]) {
if ([NSStringFromClass([childView class]) isEqualToString:@"UITransitionView"]) {
childView.frame = self.bounds;
if (depth > 1) {
[childView forceLayoutTransitionViewsToDepth:(depth - 1)];
}
}
}
}
}
@end
Now, in every view controller (or in common superclass):
#import "UIViewController+TheTweak.h"
... // whatever goes here
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self transitionViewForceLayoutTweak];
}
Or your can just turn background of problematic controller black :)