preferredStatusBarStyle не называется
я следовал этой теме переопределить -preferredStatusBarStyle, но это не называется. 
Есть ли какие-либо варианты, которые я могу изменить, чтобы включить его? (Я использую XIBs в своем проекте.)
21 ответов
возможные причины
у меня была та же проблема, и я понял, что это происходит, потому что я не устанавливал контроллер корневого представления в окне приложения.
на 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 to NO в файл plist, если вы используете этот метод.
для тех, кто использует UINavigationController:
на UINavigationController не на preferredStatusBarStyle вызовы его дочерних контроллеров представления. Вместо этого он управляет своим собственным состоянием - как и должно быть, он рисует вверху экрана, где живет строка состояния, и поэтому должен нести за нее ответственность. Поэтому реализация preferredStatusBarStyle в ваших VCs в навигационном контроллере ничего не будет делать - они никогда не будут вызываться.
фокус в том, что UINavigationController использует, чтобы решить, за чем возвращаться UIStatusBarStyleDefault или UIStatusBarStyleLightContent. Это основано на его UINavigationBar.barStyle. Значение по умолчанию (UIBarStyleDefault) результаты на темном переднем плане UIStatusBarStyleDefault строка состояния. И UIBarStyleBlack даст UIStatusBarStyleLightContent строка состояния.
TL; DR:
если вы хотите UIStatusBarStyleLightContent на UINavigationController использование:
self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
поэтому я фактически добавил категорию В UINavigationController, но использовал методы:
-(UIViewController *)childViewControllerForStatusBarStyle;
-(UIViewController *)childViewControllerForStatusBarHidden;
и они возвращают текущий видимый UIViewController. Это позволяет текущему контроллеру видимого вида установить свой собственный предпочтительный стиль / видимость.
вот полный фрагмент кода для этого:
В Swift:
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:
В Swift
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
}
наконец, убедитесь, что ваше приложение plist делает не установите для параметра" внешний вид строки состояния на основе контроллера вида " значение нет. Либо удалите эту строку, либо установите ее в YES (что, я считаю, теперь по умолчанию для iOS 7?)
для тех, кто все еще борется с этим, это простое расширение в swift должно решить проблему для вас.
extension UINavigationController {
    override open var childViewControllerForStatusBarStyle: UIViewController? {
        return self.topViewController
    }
}
Тайсон ответ правильный для изменения цвета строки состояния на белый в UINavigationController.
если кто-то хочет достичь того же результата, написав код в AppDelegate затем используйте ниже код и напишите его внутри AppDelegate's didFinishLaunchingWithOptions метод.
и не забудьте установить UIViewControllerBasedStatusBarAppearance to YES в рамках .plist файл, иначе изменение не отразится.
код
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
     // status bar appearance code
     [[UINavigationBar appearance] setBarStyle:UIBarStyleBlack];
     return YES;
}
дополнение к ответу Hippo: если вы используете 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
это решение, вероятно, лучше, чем переход к скорому устаревшему поведению.
@serenn это!--5-->ответ выше по-прежнему является отличным для случая 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
}
Если ваш viewController находится под UINavigationController.
подкласс UINavigationController и добавить
override var preferredStatusBarStyle: UIStatusBarStyle {
    return topViewController?.preferredStatusBarStyle ?? .default
}
в файле ViewController preferredStatusBarStyle будет называться.
мое приложение использовало все три: 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
    }
}
UIStatusBarStyle в iOS 7
строка состояния в iOS 7 прозрачна,вид за ней отображается.
стиль строки состояния относится к появлению ее содержимого. В iOS 7 содержимое строки состояния либо темное (UIStatusBarStyleDefault) или света (UIStatusBarStyleLightContent). Оба!--3--> и 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 file и дайте ему значение NO.
Если кто-то использует навигационный контроллер и хочет, чтобы все их навигационные контроллеры имели черный стиль, вы можете написать расширение для UINavigationController, как это в Swift 3, и оно будет применяться ко всем навигационным контроллерам (вместо того, чтобы назначать его одному контроллеру за раз).
extension UINavigationController {
    override open func viewDidLoad() {
        super.viewDidLoad()
        self.navigationBar.barStyle = UIBarStyle.black
    }
}
на 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 {
    public override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }
    public override var childViewControllerForStatusBarStyle: UIViewController? {
        return nil
    }
}
Swift 3 iOS 10 Решение:
override var preferredStatusBarStyle: UIStatusBarStyle {
    return .lightContent
 }
вот мой метод решения этой проблемы.
определите протокол под названием AGViewControllerAppearance.
AGViewControllerAppearance.h
#import <Foundation/Foundation.h>
@protocol AGViewControllerAppearance <NSObject>
@optional
- (BOOL)showsStatusBar;
- (BOOL)animatesStatusBarVisibility;
- (UIStatusBarStyle)preferredStatusBarStyle;
- (UIStatusBarAnimation)prefferedStatusBarAnimation;
@end
определить категорию по UIViewController под названием обновление.
UIViewController + Обновление.h
#import <UIKit/UIKit.h>
@interface UIViewController (Upgrade)
//
//  Replacements
//
- (void)upgradedViewWillAppear:(BOOL)animated;
@end
UIViewController + Обновление.м
#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 + Обновление сделаете правильный настройка на основе предоставленных ими значений.
Если кто-то столкнется с этой проблемой с UISearchController. Просто создайте новый подкласс UISearchController, а затем добавьте код ниже в этот класс:
override func preferredStatusBarStyle() -> UIStatusBarStyle {
    return .LightContent
}
в Swift для любого вида UIViewController:
в своем AppDelegate set:
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 да в Info.plist чтобы сделать эту работу (по умолчанию).
обратите внимание, что при использовании self.navigationController.navigationBar.barStyle = UIBarStyleBlack; решение
Не забудьте перейти к plist и установить "вид на основе контроллера строки состояния" да. Если его нет, он не будет работать.
в дополнение к ответу серенна, если вы представляете контроллер вида с modalPresentationStyle (например,.overCurrentContext), вы также должны вызвать это на вновь представленном контроллере представления:
presentedViewController.modalPresentationCapturesStatusBarAppearance = true
не забудьте также переопределить preferredStatusBarStyle В представленном контроллере вида.
большинство ответов не включают хорошую реализацию childViewControllerForStatusBarStyle метод UINavigationController. По моему опыту, вы должны обрабатывать такие случаи, когда прозрачный контроллер представления представлен над навигационным контроллером. В этих случаях вы должны передать управление своему модальному контроллеру (visibleViewController), но не тогда, когда оно исчезает.
override var childViewControllerForStatusBarStyle: UIViewController? {
  var childViewController = visibleViewController
  if let controller = childViewController, controller.isBeingDismissed {
    childViewController = topViewController
  }
  return childViewController?.childViewControllerForStatusBarStyle ?? childViewController
}
чтобы изменить цвет текста строки состояния в iOS 10 & iOS 11:
Ниже приведены случаи появления строки состояния на основе ViewController:
1) ViewController без NavigationController:
-(UIStatusBarStyle)preferredStatusBarStyle {
      return UIStatusBarStyleLightContent;// Change according to your need
}
2) ViewController с NavigationController:
self.navigationController.navigationBar.barStyle = UIStatusBarStyleLightContent; // Change according to your need
ниже для изменения цвета текста строки состояния для всего приложения:
a) Add "View controller-based status bar appearance" in info.plist and set it to NO
b) Write following code in didFinishLaunchingWithOptions in AppDelegate as:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
       [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent; // Change according to your need
       return YES;
   } 
NavigationController или TabBarController-это те, которые должны предоставить стиль. Вот как я решил:https://stackoverflow.com/a/39072526/242769
