wake-up-neo.com

preferredStatusBarStyle wird nicht aufgerufen

Ich folgte diesem Thread , um -preferredStatusBarStyle zu überschreiben, aber es wird nicht aufgerufen. Gibt es Optionen, die ich ändern kann, um sie zu aktivieren? (Ich verwende XIBs in meinem Projekt.)

224
trgoofi

Mögliche Ursache

Ich hatte das gleiche Problem und stellte fest, dass dies der Fall war, weil ich den Root-View-Controller nicht in meinem Anwendungsfenster eingestellt hatte. 

Das UIViewController, in dem ich das preferredStatusBarStyle implementiert hatte, wurde in einem UITabBarController verwendet, das das Erscheinungsbild der Ansichten auf dem Bildschirm kontrollierte.

Wenn ich den Root-View-Controller so eingestellt habe, dass er auf dieses UITabBarController-Objekt verweist, funktionierten die Statusleisten wie erwartet ordnungsgemäß (und die preferredStatusBarStyle-Methode wurde aufgerufen).

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

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

Alternative Methode (In iOS 9 nicht mehr empfohlen)

Alternativ können Sie je nach Hintergrundfarbe in jedem Ihrer View-Controller eine der folgenden Methoden aufrufen, anstatt setNeedsStatusBarAppearanceUpdate zu verwenden:

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];

oder

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];

Beachten Sie, dass Sie UIViewControllerBasedStatusBarAppearance in der plist-Datei auf NO setzen müssen, wenn Sie diese Methode verwenden.

112
AbdullahC

Für alle, die einen UINavigationController verwenden:

UINavigationController leitet Anrufe bei preferredStatusBarStyle nicht an seine untergeordneten Ansichtscontroller weiter. Stattdessen verwaltet es seinen eigenen Status - wie es sollte, zeichnet es oben auf dem Bildschirm, wo sich die Statusleiste befindet, und sollte daher dafür verantwortlich sein. Die Implementierung von preferredStatusBarStyle in Ihren VCs in einem Nav-Controller führt zu nichts - sie werden niemals aufgerufen.

Der Trick ist, was das UINavigationController verwendet, um zu entscheiden, was für UIStatusBarStyleDefault oder UIStatusBarStyleLightContent zurückgegeben werden soll. Dies basiert auf seinem UINavigationBar.barStyle. Die Standardeinstellung (UIBarStyleDefault) führt zu der dunklen Vordergrundvorderleiste UIStatusBarStyleDefault. Und UIBarStyleBlack gibt eine UIStatusBarStyleLightContent-Statusleiste aus.

TL; DR:

Wenn Sie UIStatusBarStyleLightContent für ein UINavigationController verwenden möchten, verwenden Sie:

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

Also habe ich tatsächlich eine Kategorie zu UINavigationController hinzugefügt, aber die Methoden verwendet: 

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

und mussten diese den aktuellen sichtbaren UIViewController zurückgeben. Dadurch kann der aktuelle Controller für sichtbare Ansichten seinen eigenen bevorzugten Stil/Sichtbarkeit festlegen.

Hier ist ein vollständiges Code-Snippet:

In Swift:

extension UINavigationController {

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

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

In Ziel-C:

@interface UINavigationController (StatusBarStyle)

@end

@implementation UINavigationController (StatusBarStyle)

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

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

@end

Und um es gut zu machen, hier ist, wie es dann in einem UIViewController implementiert wird:

In Swift

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

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

In Ziel-C

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

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

Vergewissern Sie sich schließlich, dass in Ihrer App-ListeNICHTdie Option "View Controller-based Statusbar" angezeigt wird. Löschen Sie entweder diese Zeile oder setzen Sie sie auf YES (was ist meiner Meinung nach jetzt die Standardeinstellung für iOS 7?)

90
serenn

Für alle, die noch Probleme damit haben, sollte diese einfache Erweiterung in Swift das Problem für Sie beheben.

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

Die Antwort von Tyson ist für das Ändern der Farbe der Statusleiste in Weiß in UINavigationController korrekt.

Wenn jemand dasselbe Ergebnis durch Schreiben des Codes in AppDelegate erzielen möchte, verwenden Sie den folgenden Code und schreiben Sie ihn in die AppDelegate'sdidFinishLaunchingWithOptions-Methode.

Vergessen Sie nicht, die Variable UIViewControllerBasedStatusBarAppearance in der .plist-Datei auf YES zu setzen. Andernfalls wird die Änderung nicht übernommen.

Code

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

     return YES;
}
14
Yogesh Suthar

Ein Zusatz zu Hippos Antwort: Wenn Sie einen UINavigationController verwenden, ist es wahrscheinlich besser, eine Kategorie hinzuzufügen:

//  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

Diese Lösung ist wahrscheinlich besser, als auf ein bald veraltetes Verhalten umzusteigen.

9
Artem Abramov

In meiner App wurden alle drei Funktionen verwendet: UINavigationController, UISplitViewController, UITabBarController, so dass diese alle die Kontrolle über die Statusleiste übernehmen und preferedStatusBarStyle nicht für ihre Kinder aufgerufen werden. Um dieses Verhalten zu überschreiben, können Sie eine Erweiterung erstellen, wie in den übrigen Antworten erwähnt. Hier ist eine Erweiterung für alle drei, in Swift 4. Ich wünschte mir, Apple würde sich mit diesen Sachen klarer auskennen.

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

Auf einem UINavigationController wird preferredStatusBarStyle nicht aufgerufen, da seine topViewController der self vorgezogen wird. Um preferredStatusBarStyle für einen UINavigationController aufgerufen zu bekommen, müssen Sie dessen childViewControllerForStatusBarStyle ändern.

Um dies für einen UINavigationController zu tun (meine Empfehlung):

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

Um dies für alle UINavigationController zu tun (Warnung: Dies betrifft UIDocumentPickerViewController, UIImagePickerController usw.):

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

@ serenns answer oben ist immer noch großartig für den Fall von UINavigationControllers. Für Swift 3 wurden jedoch die childViewController-Funktionen in vars geändert. Der UINavigationController-Erweiterungscode sollte also lauten: 

override open var childViewControllerForStatusBarStyle: UIViewController? {
  return topViewController
}

override open var childViewControllerForStatusBarHidden: UIViewController? {
  return topViewController
}

Und dann im Ansichts-Controller, der den Stil der Statusleiste bestimmen sollte: 

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

Wenn sich Ihr viewController unter UINavigationController befindet.

Unterklasse UINavigationController und add

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

ViewControllers preferredStatusBarStyle wird aufgerufen.

5
PowHu

Swift 4.2 und höher

Wie in ausgewählte Antwort erwähnt, besteht die Hauptursache darin, Ihr Fenster-Root-View-Controller-Objekt zu überprüfen.

Mögliche Fälle Ihrer Ablaufstruktur

  • Benutzerdefiniertes UIViewController-Objekt ist Windows-Stammansichts-Controller

    Ihr Window Root View Controller ist ein UIViewController-Objekt und fügt je nach Anwendungsfluss einen Navigationscontroller oder einen tabController hinzu oder entfernt ihn.

    Diese Art von Fluss wird normalerweise verwendet, wenn Ihre App einen Voranmeldungsfluss auf dem Navigationsstapel ohne Registerkarten und einen Nachanmeldungsfluss mit Registerkarten hat und möglicherweise jede Registerkarte den Navigationscontroller enthält.

  • TabBarController-Objekt ist der Fensterstammansicht-Controller

    Dies ist der Ablauf, in dem der Fensterstammansicht-Controller tabBarController ist. Möglicherweise enthält jeder Tab den Navigations-Controller.

  • Das NavigationController-Objekt ist der Window Root View Controller

    Dies ist der Ablauf, in dem der Fensterstammansicht-Controller navigationController ist.

    Ich bin nicht sicher, ob es eine Möglichkeit gibt, einem vorhandenen Navigationscontroller einen Tab-Leisten-Controller oder einen neuen Navigationscontroller hinzuzufügen. In diesem Fall müssen wir das Steuerelement für den Statusleistenstil an den nächsten Container übergeben. Also habe ich die gleiche Überprüfung in der UINavigationController-Erweiterung hinzugefügt, um childForStatusBarStyle zu finden.

Folgende Erweiterungen verwenden, es werden alle oben genannten Szenarien behandelt -

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
    }
}
  • Sie müssen UIViewControllerBasedStatusBarAppearance nicht in info.plist eingeben, da dies standardmäßig der Fall ist

Bei komplexeren Abläufen zu berücksichtigende Punkte

  • Wenn Sie einen neuen Flow modal präsentieren, wird er vom vorhandenen Statusleistenstil-Flow getrennt. Angenommen, Sie präsentieren NewFlowUIViewController und fügen dann NewFlowUIViewController einen neuen Navigations- oder TabBar-Controller hinzu. Anschließend fügen Sie eine Erweiterung von NewFlowUIViewController hinzu, um den Statusleistenstil des weiteren View-Controllers zu verwalten.

  • Wenn Sie für die modale Darstellung einen anderen modalPresentationStyle als fullScreen festlegen, müssen Sie modalPresentationCapturesStatusBarAppearance auf true setzen, damit der dargestellte Ansichts-Controller dies tun muss Erhalten Sie die Kontrolle über das Erscheinungsbild der Statusleiste.

5

UIStatusBarStyle in iOS 7

Die Statusleiste in iOS 7 ist transparent, die dahinterliegende Ansicht ist durchsichtig.

Der Stil der Statusleiste bezieht sich auf das Erscheinungsbild des Inhalts. In iOS 7 ist der Inhalt der Statusleiste entweder dunkel (UIStatusBarStyleDefault) oder hell (UIStatusBarStyleLightContent). Sowohl UIStatusBarStyleBlackTranslucent als auch UIStatusBarStyleBlackOpaque werden in iOS 7.0 nicht mehr unterstützt. Verwenden Sie stattdessen UIStatusBarStyleLightContent.

UIStatusBarStyle ändern

Wenn sich unter der Statusleiste eine Navigationsleiste befindet, wird der Statusleistenstil an den Navigationsleistenstil (UINavigationBar.barStyle) angepasst:

Wenn der Navigationsleistenstil UIBarStyleDefault ist, wird der Statusleistenstil UIStatusBarStyleDefault sein. Wenn der Navigationsleistenstil UIBarStyleBlack ist, wird der Statusleistenstil UIStatusBarStyleLightContent sein.

Wenn sich unter der Statusleiste keine Navigationsleiste befindet, kann der Statusleistenstil während der Ausführung der App von einem einzelnen View-Controller gesteuert und geändert werden.

-[UIViewController preferredStatusBarStyle] ist eine neue Methode, die in iOS 7 hinzugefügt wurde. Sie kann überschrieben werden, um den bevorzugten Statusleistenstil zurückzugeben:

- (UIStatusBarStyle)preferredStatusBarStyle
  {
      return UIStatusBarStyleLightContent;
  }

Wenn der Statusleistenstil nicht von self, sondern von einem untergeordneten Ansichtscontroller gesteuert werden soll, überschreiben Sie -[UIViewController childViewControllerForStatusBarStyle], um diesen untergeordneten Viewcontroller zurückzugeben.

Wenn Sie dieses Verhalten lieber ablehnen und den Statusleistenstil mit der -[UIApplication statusBarStyle]-Methode festlegen möchten, fügen Sie der Info.plist-Datei einer App den Schlüssel UIViewControllerBasedStatusBarAppearance hinzu und geben Sie den Wert NO an.

4
oscarr

Wenn jemand einen Navigationscontroller verwendet und wünscht, dass alle Navigationscontroller den schwarzen Stil haben, können Sie eine Erweiterung für UINavigationController wie diese in Swift 3 schreiben, die auf alle Navigationscontroller angewendet wird (anstatt sie einem Controller an einem Controller zuzuordnen Zeit).

extension UINavigationController {

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

        self.navigationBar.barStyle = UIBarStyle.black
    }

}
4
Benjamin Lowry

Wenn Sie einen View-Controller mit einer modalPresentationStyle (z. B. .overCurrentContext) präsentieren, sollten Sie zusätzlich zu serenns Antwort dies auch auf dem neu präsentierten View-Controller aufrufen:

presentedViewController.modalPresentationCapturesStatusBarAppearance = true

Vergessen Sie nicht, auch die preferredStatusBarStyle im dargestellten View-Controller zu überschreiben.

2
frin

Swift 3 iOS 10 Lösung:

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

Wenn jemand auf dieses Problem mit UISearchController stößt ..__ Erstellen Sie einfach eine neue Unterklasse von UISearchController, und fügen Sie der Klasse folgenden Code hinzu:

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

In Swift für jede Art von UIViewController:

In Ihrem AppDelegate-Set:

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

myRootController kann jede Art von UIViewController sein, z.B. UITabBarController oder UINavigationController.

Überschreiben Sie dann diesen Root-Controller wie folgt:

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

Dadurch wird die Darstellung der Statusleiste in Ihrer gesamten App geändert, da der Root-Controller allein für die Darstellung der Statusleiste verantwortlich ist.

Denken Sie daran, die Eigenschaft View controller-based status bar appearance in Ihrem Info.plist auf YES zu setzen, damit dies funktioniert (dies ist der Standard).

0
Damnum

Die meisten Antworten enthalten keine gute Implementierung der childViewControllerForStatusBarStyle-Methode für UINavigationController. Nach meiner Erfahrung sollten Sie mit solchen Fällen umgehen, wenn der transparente View-Controller über den Navigations-Controller angezeigt wird. In diesen Fällen sollten Sie die Kontrolle an Ihren modalen Controller (visibleViewController) übergeben, nicht jedoch, wenn er verschwindet.

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

Hier ist meine Methode, dies zu lösen.

Definieren Sie ein Protokoll namens AGViewControllerAppearance .

AGViewControllerAppearance.h

#import <Foundation/Foundation.h>

@protocol AGViewControllerAppearance <NSObject>

@optional

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

@end

Definieren Sie eine Kategorie auf UIViewController genannt 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

Nun ist es Zeit zu sagen, dass der View Controller das AGViewControllerAppearance Protokoll implementiert.

Beispiel:

@interface XYSampleViewController () <AGViewControllerAppearance>

... the rest of the interface

@end

Natürlich können Sie die restlichen Methoden ( showsStatusBar , animatesStatusBarVisibility , prefferedStatusBarAnimation ) aus dem Protokoll implementieren und UIViewController + Upgrade führt die entsprechende .__ auf den von ihnen angegebenen Werten.

0
arturgrigor

Beachten Sie dies, wenn Sie die self.navigationController.navigationBar.barStyle = UIBarStyleBlack;-Lösung verwenden

gehen Sie sicher, dass Sie zu Ihrer Liste gehen und "Anzeige Controller-basierter Statusleiste anzeigen" auf YES setzen. Wenn nein, funktioniert es nicht. 

0