First, my app's setup:
Most of the app's view controllers exist in your standard navigation controller hierarchy, but I also have a second window over the main app window, which hosts a view controller (NotificationVC
). If NotificationVC
is presenting a notification, it will change the status bar style to contrast with the notifications, but otherwise it defers the style to the main window's root view controller.
My issue is that changes in the main window that would normally trigger a status bar appearance update (pushing, popping or presenting a view controller, or calling -[UIViewController setNeedsStatusBarAppearanceUpdate]
) have no effect.
Here's the relevant code from NotificationVC
:
@implementation NotificationVC
- (UIStatusBarStyle)preferredStatusBarStyle
{
if (self.isShowingNotification)
{
if (self.notificationView.hasDarkBackground)
{
return UIStatusBarStyleLightContent;
}
else
{
return UIStatusBarStyleDefault;
}
}
else
{
return [[UIApplication sharedApplication].delegate window].rootViewController.preferredStatusBarStyle;
}
}
@end
How can I get the status bar to update from one of the view controllers in the main window?
Note: Manually setting the status bar appearance (-[UIApplication setStatusBarStyle:]
) is not an acceptable solution for this app.
This seems to be an optimization on UIViewController
's part - it won't trigger an update if it isn't in the top window.
I was able to work around the issue by swizzling out UIViewController
's implementation of setNeedsStatusAppearanceUpdate
for one that is aware of the notification view controller's window.
@interface UIViewController (NotificationWindow)
@end
@implementation UIViewController (NotificationWindow)
+ (void)load
{
Method original = class_getInstanceMethod([UIViewController class], @selector(setNeedsStatusBarAppearanceUpdate));
Method swizzled = class_getInstanceMethod([UIViewController class], @selector(swiz_setNeedsStatusBarAppearanceUpdate));
method_exchangeImplementations(original, swizzled);
}
- (void)swiz_setNeedsStatusBarAppearanceUpdate
{
UIWindow *topWindow = [UIApplication sharedApplication].windows.lastObject;
if (![self.view.window isEqual:topWindow] && [topWindow.rootViewController isKindOfClass:[NotificationVC class]])
{
[[[UIApplication sharedApplication].windows.lastObject rootViewController] swiz_setNeedsStatusBarAppearanceUpdate];
}
else
{
[self swiz_setNeedsStatusBarAppearanceUpdate];
}
}
@end
It's a little hacky — I try to avoid swizzling — but it allows the status bar appearance API to work as-is, without requiring every other view controller to be aware of NotificationVC
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With