J'ai suivi ce fil pour remplacer -preferredStatusBarStyle
, mais ce n'est pas appelé. Y a-t-il des options que je peux changer pour l'activer? (J'utilise des XIB dans mon projet.)
J'ai eu le même problème et j'ai compris que c'était parce que je ne configurais pas le contrôleur de vue racine dans la fenêtre de l'application.
La UIViewController
dans laquelle j'avais implémenté la preferredStatusBarStyle
était utilisée dans une UITabBarController
, qui contrôlait l'affichage des vues à l'écran.
Lorsque je configure le contrôleur de vue racine pour qu'il pointe vers cette UITabBarController
, les modifications de la barre d'état ont commencé à fonctionner correctement, comme prévu (et la méthode preferredStatusBarStyle
a été appelée).
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
... // other view controller loading/setup code
self.window.rootViewController = rootTabBarController;
[self.window makeKeyAndVisible];
return YES;
}
Vous pouvez également appeler l'une des méthodes suivantes, selon le cas, dans chacun de vos contrôleurs de vue, en fonction de la couleur d'arrière-plan, au lieu de devoir utiliser setNeedsStatusBarAppearanceUpdate
:
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
ou
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];
Notez que vous devez également définir UIViewControllerBasedStatusBarAppearance
sur NO
dans le fichier plist si vous utilisez cette méthode.
Pour toute personne utilisant un contrôleur UINavigation:
La UINavigationController
ne transfère pas les appels preferredStatusBarStyle
à ses contrôleurs de vue enfant. Au lieu de cela, il gère son propre état - comme il se doit, il dessine en haut de l'écran l'emplacement de la barre d'état. Par conséquent, implémenter preferredStatusBarStyle
dans vos VCs dans un contrôleur de navigation ne fera rien - ils ne seront jamais appelés.
L’astuce consiste à utiliser ce que UINavigationController
utilise pour décider quoi retourner pour UIStatusBarStyleDefault
ou UIStatusBarStyleLightContent
. Il se base sur son UINavigationBar.barStyle
. La valeur par défaut (UIBarStyleDefault
) entraîne l'affichage de la barre d'état UIStatusBarStyleDefault
au premier plan sombre. Et UIBarStyleBlack
donnera une barre UIStatusBarStyleLightContent
.
TL; DR:
Si vous voulez UIStatusBarStyleLightContent
sur une UINavigationController
, utilisez:
self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
J'ai donc ajouté une catégorie à UINavigationController, mais j'ai utilisé les méthodes suivantes:
-(UIViewController *)childViewControllerForStatusBarStyle;
-(UIViewController *)childViewControllerForStatusBarHidden;
et ont renvoyé le UIViewController visible en cours. Cela permet au contrôleur de vue visible actuel de définir son propre style/visibilité.
Voici un extrait de code complet pour cela:
En rapide:
extension UINavigationController {
public override func childViewControllerForStatusBarHidden() -> UIViewController? {
return self.topViewController
}
public override func childViewControllerForStatusBarStyle() -> UIViewController? {
return self.topViewController
}
}
En Objective-C:
@interface UINavigationController (StatusBarStyle)
@end
@implementation UINavigationController (StatusBarStyle)
-(UIViewController *)childViewControllerForStatusBarStyle {
return self.topViewController;
}
-(UIViewController *)childViewControllerForStatusBarHidden {
return self.topViewController;
}
@end
Et pour faire bonne mesure, voici comment cela est implémenté dans un UIViewController:
En rapide
override public func preferredStatusBarStyle() -> UIStatusBarStyle {
return .LightContent
}
override func prefersStatusBarHidden() -> Bool {
return false
}
En Objective-C
-(UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleLightContent; // your own style
}
- (BOOL)prefersStatusBarHidden {
return NO; // your own visibility code
}
Enfin, assurez-vous que la pliste de votre application ET QUE ne présente pas «L'apparence de la barre d'état basée sur le contrôleur d'affichage» définie sur NO. Supprimez cette ligne ou définissez-la sur OUI (qui, à mon avis, est la valeur par défaut pour iOS 7?)
Pour ceux qui ont encore du mal à résoudre ce problème, cette simple extension de Swift devrait résoudre le problème pour vous.
extension UINavigationController {
override open var childViewControllerForStatusBarStyle: UIViewController? {
return self.topViewController
}
}
La réponse de Tyson est correcte pour changer la couleur de la barre d'état en blanc dans UINavigationController
.
Si quelqu'un veut obtenir le même résultat en écrivant le code dans AppDelegate
, utilisez le code ci-dessous et écrivez-le dans la méthode AppDelegate's
didFinishLaunchingWithOptions
.
Et n'oubliez pas de définir UIViewControllerBasedStatusBarAppearance
sur YES
dans le fichier .plist, sinon la modification ne sera pas reflétée.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// status bar appearance code
[[UINavigationBar appearance] setBarStyle:UIBarStyleBlack];
return YES;
}
Un ajout à la réponse d'Hippo: si vous utilisez un contrôleur UINavigation, il est probablement préférable d'ajouter une catégorie:
// 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
Cette solution est probablement meilleure que de passer à un comportement bientôt obsolète.
Mon application utilisait les trois: UINavigationController
, UISplitViewController
, UITabBarController
, de sorte qu'ils semblent tous prendre le contrôle de la barre d'état et feront en sorte que preferedStatusBarStyle
ne sera pas appelé pour leurs enfants. Pour remplacer ce comportement, vous pouvez créer une extension comme le reste des réponses l’ont mentionné. Voici une extension pour les trois, dans Swift 4. Souhaitez que Apple soit plus clair sur ce genre de choses.
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
}
}
Sur un contrôleur UINavigation, preferredStatusBarStyle
n'est pas appelé car sa topViewController
est préférée à self
. Ainsi, pour que preferredStatusBarStyle
soit appelé sur un UINavigationController, vous devez changer sa childViewControllerForStatusBarStyle
.
Pour le faire pour un contrôleur UINavigation (ma recommandation):
class MyRootNavigationController: UINavigationController {
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
override var childViewControllerForStatusBarStyle: UIViewController? {
return nil
}
}
Pour le faire pour tous les UINavigationController (avertissement: cela affecte UIDocumentPickerViewController, UIImagePickerController, etc.):
extension UINavigationController {
open override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
open override var childViewControllerForStatusBarStyle: UIViewController? {
return nil
}
}
@ serenn's answer above est toujours une excellente solution pour le cas des contrôleurs UINavigation. Cependant, pour Swift 3, les fonctions childViewController ont été remplacées par vars
. Donc, le code d'extension UINavigationController
devrait être:
override open var childViewControllerForStatusBarStyle: UIViewController? {
return topViewController
}
override open var childViewControllerForStatusBarHidden: UIViewController? {
return topViewController
}
Et puis dans le contrôleur de vue qui devrait dicter le style de la barre d'état:
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
Si votre viewController est sous UINavigationController.
Sous-classe UINavigationController et ajouter
override var preferredStatusBarStyle: UIStatusBarStyle {
return topViewController?.preferredStatusBarStyle ?? .default
}
La variable preferredStatusBarStyle
de ViewController sera appelée.
Comme mentionné dans réponse sélectionnée , la cause première est de vérifier votre objet Contrôleur de vue racine de fenêtre.
childForStatusBarStyle
Utilisez les extensions suivantes, il gère tous les scénarios ci-dessus -
extension UITabBarController {
open override var childForStatusBarStyle: UIViewController? {
return selectedViewController?.childForStatusBarStyle ?? selectedViewController
}
}
extension UINavigationController {
open override var childForStatusBarStyle: UIViewController? {
return topViewController?.childForStatusBarStyle ?? topViewController
}
}
extension AppRootViewController {
open override var preferredStatusBarStyle: UIStatusBarStyle {
return children.first { $0.childForStatusBarStyle != nil }?.childForStatusBarStyle?.preferredStatusBarStyle ?? .default
}
}
UIViewControllerBasedStatusBarAppearance
dans info.plist
car elle est vraie par défautSi vous présentez un nouveau flux de manière modale, il se détache du flux de style de barre d’état existant. Supposons donc que vous présentiez un NewFlowUIViewController
, puis que vous ajoutiez un nouveau contrôleur de navigation ou de tabulation à NewFlowUIViewController
, puis que vous ajoutiez l'extension de NewFlowUIViewController
pour gérer davantage le style de barre d'état du contrôleur de vue.
Si vous définissez modalPresentationStyle autre que fullScreen
lors d'une présentation modale, vous devez définir modalPresentationCapturesStatusBarAppearance
sur true, de sorte que le contrôleur de vue présenté doit recevoir le contrôle de l'apparence de la barre d'état.
UIStatusBarStyle dans iOS 7
La barre d'état dans iOS 7 est transparente, la vue derrière elle est visible.
Le style de la barre d'état fait référence aux apparences de son contenu. Dans iOS 7, le contenu de la barre d'état est sombre (UIStatusBarStyleDefault
) ou clair (UIStatusBarStyleLightContent
). UIStatusBarStyleBlackTranslucent
et UIStatusBarStyleBlackOpaque
sont obsolètes dans iOS 7.0. Utilisez UIStatusBarStyleLightContent
à la place.
Comment changer UIStatusBarStyle
Si sous la barre d'état se trouve une barre de navigation, le style de la barre d'état sera ajusté pour correspondre au style de la barre de navigation (UINavigationBar.barStyle
):
Plus précisément, si le style de la barre de navigation est UIBarStyleDefault, le style de la barre d'état sera UIStatusBarStyleDefault
; Si le style de la barre de navigation est UIBarStyleBlack
, le style de la barre d'état sera UIStatusBarStyleLightContent
.
S'il n'y a pas de barre de navigation en dessous de la barre d'état, le style de la barre d'état peut être contrôlé et modifié par un contrôleur de vue individuel pendant l'exécution de l'application.
-[UIViewController preferredStatusBarStyle]
est une nouvelle méthode ajoutée dans iOS 7. Vous pouvez le remplacer pour renvoyer le style de barre d'état préféré:
- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
Si le style de la barre d'état doit être contrôlé par un contrôleur de vue enfant au lieu de lui-même, remplacez -[UIViewController childViewControllerForStatusBarStyle]
pour renvoyer ce contrôleur de vue enfant.
Si vous préférez désactiver ce comportement et définir le style de la barre d'état à l'aide de la méthode -[UIApplication statusBarStyle]
, ajoutez la clé UIViewControllerBasedStatusBarAppearance
au fichier Info.plist
de l'application et attribuez-lui la valeur NO.
Si quelqu'un utilise un contrôleur de navigation et souhaite que tous ses contrôleurs de navigation aient le style noir, vous pouvez écrire une extension de UINavigationController comme celle-ci dans Swift 3, qui s'appliquera à tous les contrôleurs de navigation (au lieu de l'attribuer à un contrôleur à la fois). temps).
extension UINavigationController {
override open func viewDidLoad() {
super.viewDidLoad()
self.navigationBar.barStyle = UIBarStyle.black
}
}
En plus de la réponse de serenn, si vous présentez un contrôleur de vue avec une modalPresentationStyle
(par exemple .overCurrentContext
), vous devez également appeler cela sur le nouveau contrôleur de vue présenté:
presentedViewController.modalPresentationCapturesStatusBarAppearance = true
N'oubliez pas de remplacer également la variable preferredStatusBarStyle
dans le contrôleur de vue présenté.
Solution Swift 3 iOS 10:
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
Si quelqu'un rencontre ce problème avec UISearchController ..__, créez simplement une nouvelle sous-classe de UISearchController, puis ajoutez le code ci-dessous dans cette classe:
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return .LightContent
}
Dans Swift pour tout type de UIViewController:
Dans votre ensemble AppDelegate
:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
window!.rootViewController = myRootController
return true
}
myRootController
peut être n’importe quel type de UIViewController
, par ex. UITabBarController
ou UINavigationController
.
Ensuite, remplacez ce contrôleur racine comme ceci:
class RootController: UIViewController {
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return .LightContent
}
}
Cela modifiera l'apparence de la barre d'état dans l'ensemble de votre application, car le contrôleur racine est seul responsable de l'apparence de la barre d'état.
N'oubliez pas de définir la propriété View controller-based status bar appearance
sur YES dans votre Info.plist
pour que cela fonctionne (valeur par défaut).
La plupart des réponses n'incluent pas une bonne implémentation de la méthode childViewControllerForStatusBarStyle
pour UINavigationController
. Selon mon expérience, vous devriez gérer des cas tels que ceux où le contrôleur de vue transparent est présenté sur le contrôleur de navigation. Dans ces cas, vous devriez passer le contrôle à votre contrôleur modal (visibleViewController
), mais pas lorsqu'il disparaît.
override var childViewControllerForStatusBarStyle: UIViewController? {
var childViewController = visibleViewController
if let controller = childViewController, controller.isBeingDismissed {
childViewController = topViewController
}
return childViewController?.childViewControllerForStatusBarStyle ?? childViewController
}
Voici ma méthode pour résoudre ce problème.
Définissez un protocole appelé AGViewControllerAppearance .
AGViewControllerAppearance.h
#import <Foundation/Foundation.h>
@protocol AGViewControllerAppearance <NSObject>
@optional
- (BOOL)showsStatusBar;
- (BOOL)animatesStatusBarVisibility;
- (UIStatusBarStyle)preferredStatusBarStyle;
- (UIStatusBarAnimation)prefferedStatusBarAnimation;
@end
Définissez une catégorie sur UIViewController appelé 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
Maintenant, il est temps de dire que votre contrôleur de vue implémente le protocole AGViewControllerAppearance .
Exemple:
@interface XYSampleViewController () <AGViewControllerAppearance>
... the rest of the interface
@end
Bien sûr, vous pouvez implémenter le reste des méthodes ( showsStatusBar , animatesStatusBarVisibility , prefferedStatusBarAnimation ) à partir du protocole et UIViewController + Upgrade fera les opérations appropriées sur les valeurs fournies par eux.
Notez que lorsque vous utilisez la solution self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
assurez-vous de vous rendre sur votre plist et de définir "Afficher l'apparence de la barre d'état basée sur le contrôleur" sur OUI. Si c'est NON cela ne fonctionnera pas.