Внешний вид UIStatusBar с несколькими окнами

Во-первых, моя установка приложения:

Большинство контроллеров представления приложений существуют в вашей стандартной иерархии диспетчера навигации, но у меня также есть второе окно в главном окне приложения, в котором размещается контроллер вида (NotificationVC). Если NotificationVC представляет уведомление, оно изменит стиль строки состояния, чтобы контрастировать с уведомлениями, но в противном случае он отменит стиль к контроллеру корневого представления главного окна.

Моя проблема в том, что изменения в главном окне, которые обычно запускают обновление внешнего вида строки состояния (нажатие, выскакивание или представление контроллера вида или вызов -[UIViewController setNeedsStatusBarAppearanceUpdate]) , не имеют эффекта.

Здесь соответствующий код из 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

Как я могу получить строку состояния для обновления с одного из контроллеров представления в главном окне?

Примечание. Вручную установка внешнего вида строки состояния (-[UIApplication setStatusBarStyle:]) не является приемлемым решением для этого приложения.

2 ответа

Это, по-видимому, оптимизация на части UIViewController - она ​​не будет инициировать обновление, если оно не находится в верхнем окне.

Мне удалось решить проблему, выполнив UIViewController реализацию setNeedsStatusAppearanceUpdate для тех, кто знает окно контроллера просмотра уведомлений.

@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

Немного взломанный - я стараюсь избегать swizzling, но он позволяет API-интерфейсу статуса строки работать как есть, не требуя, чтобы каждый другой контроллер представления знал о NotificationVC.


Допустим, у вас на экране есть 3 контроллера вида, vc1 vc2 vc3 и они реализуют preferredStatusBarStyle с другим внешним видом. Чтобы заставить строку статуса принять внешний вид, установленный vc1, нужно вызвать:

[vc1 setNeedsStatusBarAppearanceUpdate]

Или, конечно, ViewController также может запускать сам себя:

[self setNeedsStatusBarAppearanceUpdate]

Если вы хотите переключиться на другой макет ViewController, вы вызываете setNeedsStatusBarAppearanceUpdate на этом контроллере представления.

В качестве дополнительного бонуса вы можете анимировать такие изменения:

[UIView animateWithDuration:0.3 animations:^{
 [self setNeedsStatusBarAppearanceUpdate];
}];

licensed under cc by-sa 3.0 with attribution.