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