it-swarm.com.ru

favourStatusBarStyle не вызывается

Я следовал этой теме , чтобы переопределить -preferredStatusBarStyle, но он не вызывается. Есть ли варианты, которые я могу изменить, чтобы включить его? (Я использую XIB в моем проекте.)

224
trgoofi

Возможная первопричина

У меня была та же проблема, и я понял, что это происходит, потому что я не настраивал контроллер корневого представления в моем окне приложения. 

UIViewController, в котором я реализовал preferredStatusBarStyle, использовался в UITabBarController, который контролировал отображение представлений на экране.

Когда я установил контроллер корневого представления так, чтобы он указывал на эту UITabBarController, изменения строки состояния начали работать правильно, как и ожидалось (и вызывался метод preferredStatusBarStyle).

(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    ... // other view controller loading/setup code

    self.window.rootViewController = rootTabBarController;
    [self.window makeKeyAndVisible];
    return YES;
}

Альтернативный метод (не рекомендуется в iOS 9)

В качестве альтернативы, вы можете вызвать один из следующих методов, в зависимости от ситуации, в каждом из ваших контроллеров представления, в зависимости от его цвета фона, вместо необходимости использовать setNeedsStatusBarAppearanceUpdate:

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];

или же

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];

Обратите внимание, что вам также нужно установить UIViewControllerBasedStatusBarAppearance в NO в файле plist, если вы используете этот метод.

112
AbdullahC

Для тех, кто использует UINavigationController:

UINavigationController не перенаправляет вызовы preferredStatusBarStyle своим дочерним контроллерам представления. Вместо этого он управляет своим собственным состоянием - как и положено, он рисует в верхней части экрана, где находится строка состояния, и поэтому должен нести за него ответственность. Поэтому реализация preferredStatusBarStyle в ваших VC в контроллере nav ничего не даст - они никогда не будут вызываться.

Хитрость заключается в том, что UINavigationController использует, чтобы решить, что возвращать для UIStatusBarStyleDefault или UIStatusBarStyleLightContent. Это основано на его UINavigationBar.barStyle. Значение по умолчанию (UIBarStyleDefault) приводит к строке состояния темного переднего плана UIStatusBarStyleDefault. И UIBarStyleBlack выдаст строку состояния UIStatusBarStyleLightContent.

TL; DR:

Если вы хотите использовать UIStatusBarStyleLightContent для UINavigationController:

self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
954
Tyson

Поэтому я фактически добавил категорию в UINavigationController, но использовал следующие методы: 

-(UIViewController *)childViewControllerForStatusBarStyle;
-(UIViewController *)childViewControllerForStatusBarHidden;

и они возвращали текущий видимый UIViewController. Это позволяет текущему видимому контроллеру представления установить свой собственный предпочтительный стиль/видимость.

Вот полный фрагмент кода для этого:

В Свифте:

extension UINavigationController {

    public override func childViewControllerForStatusBarHidden() -> UIViewController? {
        return self.topViewController
    }

    public override func childViewControllerForStatusBarStyle() -> UIViewController? {
        return self.topViewController
    }
}

В Objective-C:

@interface UINavigationController (StatusBarStyle)

@end

@implementation UINavigationController (StatusBarStyle)

-(UIViewController *)childViewControllerForStatusBarStyle {
    return self.topViewController;
}

-(UIViewController *)childViewControllerForStatusBarHidden {
    return self.topViewController;
}

@end

И для хорошей меры, вот как это реализовано тогда в UIViewController:

В Свифте

override public func preferredStatusBarStyle() -> UIStatusBarStyle {
    return .LightContent
}

override func prefersStatusBarHidden() -> Bool {
    return false
}

В Objective-C

-(UIStatusBarStyle)preferredStatusBarStyle {
    return UIStatusBarStyleLightContent; // your own style
}

- (BOOL)prefersStatusBarHidden {
    return NO; // your own visibility code
}

Наконец, убедитесь, что в списке свойств приложенияНЕТдля параметра "Просмотр внешнего вида строки состояния на основе контроллера" установлено значение NO. Либо удалите эту строку, либо задайте для нее значение ДА (что, по моему мнению, является значением по умолчанию для iOS 7?)

90
serenn

Для тех, кто все еще борется с этим, это простое расширение в Swift должно решить проблему для вас.

extension UINavigationController {
    override open var childViewControllerForStatusBarStyle: UIViewController? {
        return self.topViewController
    }
}
51
Alex Brown

Ответ Тайсона правильный для изменения цвета строки состояния на белый в UINavigationController.

Если кто-то хочет добиться того же результата, написав код в AppDelegate, используйте приведенный ниже код и напишите его в методе AppDelegate'sdidFinishLaunchingWithOptions.

И не забудьте установить для UIViewControllerBasedStatusBarAppearance значение YES в файле .plist, иначе изменение не будет отражаться.

Код

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
     // status bar appearance code
     [[UINavigationBar appearance] setBarStyle:UIBarStyleBlack];

     return YES;
}
14
Yogesh Suthar

Дополнение к ответу Бегемота: если вы используете UINavigationController, то, вероятно, лучше добавить категорию:

//  UINavigationController+StatusBarStyle.h:

@interface UINavigationController (StatusBarStyle)

@end



//  UINavigationController+StatusBarStyle.m:

@implementation UINavigationController (StatusBarStyle)

- (UIStatusBarStyle)preferredStatusBarStyle
{
    //also you may add any fancy condition-based code here
    return UIStatusBarStyleLightContent;
}

@end

Это решение, вероятно, лучше, чем переключение на поведение, которое вскоре станет устаревшим.

9
Artem Abramov

Мое приложение использовало все три: UINavigationController, UISplitViewController, UITabBarController, таким образом, кажется, что все они контролируют строку состояния и приводят к тому, что preferedStatusBarStyle не будет вызываться для их детей. Чтобы изменить это поведение, вы можете создать расширение, как и в остальных ответах. Вот расширение для всех трех, в Swift 4. Хотелось бы, чтобы Apple была более ясна в этом отношении.

extension UINavigationController {
    open override var childViewControllerForStatusBarStyle: UIViewController? {
        return self.topViewController
    }

    open override var childViewControllerForStatusBarHidden: UIViewController? {
        return self.topViewController
    }
}

extension UITabBarController {
    open override var childViewControllerForStatusBarStyle: UIViewController? {
        return self.childViewControllers.first
    }

    open override var childViewControllerForStatusBarHidden: UIViewController? {
        return self.childViewControllers.first
    }
}

extension UISplitViewController {
    open override var childViewControllerForStatusBarStyle: UIViewController? {
        return self.childViewControllers.first
    }

    open override var childViewControllerForStatusBarHidden: UIViewController? {
        return self.childViewControllers.first
    }
}
9
Luis

На UINavigationController preferredStatusBarStyle не вызывается, потому что его topViewController предпочтительнее self. Итак, чтобы вызвать preferredStatusBarStyle для UINavigationController, вам нужно изменить его childViewControllerForStatusBarStyle.

Чтобы сделать это для одного UINavigationController (моя рекомендация):

class MyRootNavigationController: UINavigationController {
    override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }
    override var childViewControllerForStatusBarStyle: UIViewController? {
        return nil
    }
}

Чтобы сделать это для всех UINavigationController (предупреждение: это влияет на UIDocumentPickerViewController, UIImagePickerController и т.д.):

extension UINavigationController {
    open override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }
    open override var childViewControllerForStatusBarStyle: UIViewController? {
        return nil
    }
}
7
Cœur

@ serenn's answer выше все еще отлично подходит для случая UINavigationControllers. Однако для Swift 3 функции childViewController были изменены на vars. Таким образом, код расширения UINavigationController должен быть: 

override open var childViewControllerForStatusBarStyle: UIViewController? {
  return topViewController
}

override open var childViewControllerForStatusBarHidden: UIViewController? {
  return topViewController
}

А затем в контроллере представления, который должен диктовать стиль строки состояния: 

override var preferredStatusBarStyle: UIStatusBarStyle {
   return .lightContent
}
7
John Stricker

Если ваш viewController находится под UINavigationController.

Подкласс UINavigationController и добавить

override var preferredStatusBarStyle: UIStatusBarStyle {
    return topViewController?.preferredStatusBarStyle ?? .default
}

Будет вызван preferredStatusBarStyle ViewController.

5
PowHu

UIStatusBarStyle в iOS 7

Строка состояния в iOS 7 прозрачна, вид за ней просвечивает.

Стиль строки состояния относится к внешнему виду ее содержимого. В iOS 7 содержимое строки состояния либо темное (UIStatusBarStyleDefault), либо светлое (UIStatusBarStyleLightContent). И UIStatusBarStyleBlackTranslucent, и UIStatusBarStyleBlackOpaque устарели в iOS 7.0. Вместо этого используйте UIStatusBarStyleLightContent.

Как изменить UIStatusBarStyle

Если под строкой состояния находится панель навигации, стиль строки состояния будет скорректирован в соответствии со стилем панели навигации (UINavigationBar.barStyle):

В частности, если стиль панели навигации - UIBarStyleDefault, стиль строки состояния будет UIStatusBarStyleDefault; если стиль панели навигации - UIBarStyleBlack, стиль строки состояния будет UIStatusBarStyleLightContent.

Если под строкой состояния нет панели навигации, стиль строки состояния может контролироваться и изменяться отдельным контроллером представления во время работы приложения.

-[UIViewController preferredStatusBarStyle] - это новый метод, добавленный в iOS 7. Его можно переопределить, чтобы вернуть предпочтительный стиль строки состояния:

- (UIStatusBarStyle)preferredStatusBarStyle
  {
      return UIStatusBarStyleLightContent;
  }

Если стиль строки состояния должен контролироваться дочерним контроллером представления вместо self, переопределите -[UIViewController childViewControllerForStatusBarStyle], чтобы вернуть этот дочерний контроллер представления.

Если вы предпочитаете отказаться от этого поведения и установить стиль строки состояния с помощью метода -[UIApplication statusBarStyle], добавьте ключ UIViewControllerBasedStatusBarAppearance в файл Info.plist приложения и присвойте ему значение NO.

4
oscarr

Если кто-то использует контроллер навигации и хочет, чтобы все его контроллеры навигации имели черный стиль, вы можете написать расширение для UINavigationController, как это в Swift 3, и оно будет применяться ко всем контроллерам навигации (вместо назначения его одному контроллеру в время).

extension UINavigationController {

    override open func viewDidLoad() {
        super.viewDidLoad()

        self.navigationBar.barStyle = UIBarStyle.black
    }

}
4
Benjamin Lowry

В дополнение к ответу Серенна, если вы представляете контроллер представления с modalPresentationStyle (например, .overCurrentContext), вы должны также вызвать это на недавно представленном контроллере представления:

presentedViewController.modalPresentationCapturesStatusBarAppearance = true

Не забудьте также переопределить preferredStatusBarStyle в представленном контроллере представления.

2
frin

Решение Swift 3 для iOS 10:

override var preferredStatusBarStyle: UIStatusBarStyle {
    return .lightContent
 }
1
Statik

Если кто-то столкнулся с этой проблемой с UISearchController . Просто создайте новый подкласс UISearchController, а затем добавьте приведенный ниже код в этот класс:

override func preferredStatusBarStyle() -> UIStatusBarStyle {
    return .LightContent
}
0
Tai Le

В Swift для любого вида UIViewController:

В вашем наборе AppDelegate:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    window!.rootViewController = myRootController
    return true
}

myRootController может быть любым типом UIViewController, например, UITabBarController или UINavigationController.

Затем переопределите этот корневой контроллер следующим образом:

class RootController: UIViewController {
    override func preferredStatusBarStyle() -> UIStatusBarStyle {
        return .LightContent
    }
}

Это изменит внешний вид строки состояния во всем приложении, поскольку корневой контроллер несет полную ответственность за внешний вид строки состояния.

Не забудьте установить для свойства View controller-based status bar appearance значение YES в Info.plist, чтобы это работало (по умолчанию).

0
Damnum

Большинство ответов не включают в себя хорошую реализацию метода childViewControllerForStatusBarStyle для UINavigationController. Согласно моему опыту, вы должны обрабатывать такие случаи, когда контроллер прозрачного представления представлен поверх контроллера навигации. В этих случаях вы должны передать управление своему модальному контроллеру (visibleViewController), но не тогда, когда он исчезает.

override var childViewControllerForStatusBarStyle: UIViewController? {
  var childViewController = visibleViewController
  if let controller = childViewController, controller.isBeingDismissed {
    childViewController = topViewController
  }
  return childViewController?.childViewControllerForStatusBarStyle ?? childViewController
}
0
Timur Bernikovich

Вот мой метод решения этого.

Определите протокол с именем AGViewControllerAppearance .

AGViewControllerAppearance.h

#import <Foundation/Foundation.h>

@protocol AGViewControllerAppearance <NSObject>

@optional

- (BOOL)showsStatusBar;
- (BOOL)animatesStatusBarVisibility;
- (UIStatusBarStyle)preferredStatusBarStyle;
- (UIStatusBarAnimation)prefferedStatusBarAnimation;

@end

Определите категорию в UIViewController said Upgrade .

UIViewController + Upgrade.h

#import <UIKit/UIKit.h>

@interface UIViewController (Upgrade)

//
//  Replacements
//

- (void)upgradedViewWillAppear:(BOOL)animated;

@end

UIViewController + Upgrade.m

#import "UIViewController+Upgrade.h"

#import <objc/runtime.h>

#import "AGViewControllerAppearance.h" // This is the appearance protocol

@implementation UIViewController (Upgrade)

+ (void)load
{
#pragma clang diagnostic Push
#pragma clang diagnostic ignored "-Wselector"
    Method viewWillAppear = class_getInstanceMethod(self, @selector(viewWillAppear:));
#pragma clang diagnostic pop
    Method upgradedViewWillAppear = class_getInstanceMethod(self, @selector(upgradedViewWillAppear:));
    method_exchangeImplementations(viewWillAppear, upgradedViewWillAppear);
}

#pragma mark - Implementation

- (void)upgradedViewWillAppear:(BOOL)animated
{
    //
    //  Call the original message (it may be a little confusing that we're
    //  calling the 'same' method, but we're actually calling the original one :) )
    //

    [self upgradedViewWillAppear:animated];

    //
    //  Implementation
    //

    if ([self conformsToProtocol:@protocol(AGViewControllerAppearance)])
    {
        UIViewController <AGViewControllerAppearance> *viewControllerConformingToAppearance =
        (UIViewController <AGViewControllerAppearance> *)self;

        //
        //  Status bar
        //

        if ([viewControllerConformingToAppearance respondsToSelector:@selector(preferredStatusBarStyle)])
        {
            BOOL shouldAnimate = YES;

            if ([viewControllerConformingToAppearance respondsToSelector:@selector(animatesStatusBarVisibility)])
            {
                shouldAnimate = [viewControllerConformingToAppearance animatesStatusBarVisibility];
            }

            [[UIApplication sharedApplication] setStatusBarStyle:[viewControllerConformingToAppearance preferredStatusBarStyle]
                                                        animated:shouldAnimate];
        }

        if ([viewControllerConformingToAppearance respondsToSelector:@selector(showsStatusBar)])
        {
            UIStatusBarAnimation animation = UIStatusBarAnimationSlide;

            if ([viewControllerConformingToAppearance respondsToSelector:@selector(prefferedStatusBarAnimation)])
            {
                animation = [viewControllerConformingToAppearance prefferedStatusBarAnimation];
            }

            [[UIApplication sharedApplication] setStatusBarHidden:(! [viewControllerConformingToAppearance showsStatusBar])
                                                    withAnimation:animation];
        }
    }
}

@end

Теперь пришло время сказать, что ваш контроллер представления реализует протокол AGViewControllerAppearance .

Пример:

@interface XYSampleViewController () <AGViewControllerAppearance>

... the rest of the interface

@end

Конечно, вы можете реализовать остальные методы ( showsStatusBar , animatesStatusBarVisibility , prefferedStatusBarAnimation ) из протокола и UIViewController + Upgrade будет делать правильную настройку на основе на значения, предоставленные ими.

0
arturgrigor

Обратите внимание, что при использовании решения self.navigationController.navigationBar.barStyle = UIBarStyleBlack;

обязательно зайдите в свой список и установите «Просмотр внешнего вида строки состояния на основе контроллера» на ДА. Если его нет, он не будет работать. 

0
Richard Garfield