bevorzugtStatusBarStyle wird nicht aufgerufen

257

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

trgoofi
quelle
In welchem ​​Kontext wird es nicht aufgerufen: Simulator? auf einem Gerät?
Nur
@bneely beide.
Trgoofi
Sie verwenden den iOS 7-Simulator, ein iOS 7-Gerät, und Ihr Basis-SDK ist 7.0?
Bneely
@bneely iOS SDK 7.0 wird unter meinem Projektnamen angezeigt. Bedeutet das, dass mein Basis-SDK 7.0 ist?
Trgoofi
In den Build-Einstellungen wird im "Basis-SDK" der Wert festgelegt. Es hört sich so an, als ob Ihr Projekt auf 7.0 eingestellt ist.
Nur

Antworten:

117

Mögliche Grundursache

Ich hatte das gleiche Problem und stellte fest, dass es passierte, weil ich den Root-View-Controller nicht in meinem Anwendungsfenster eingestellt hatte.

Das, UIViewControllerin dem ich das implementiert hatte, preferredStatusBarStylewurde in einem verwendet UITabBarController, das das Erscheinungsbild der Ansichten auf dem Bildschirm kontrollierte.

Als ich den Root-View-Controller so einstellte UITabBarController, dass er darauf hinweist, funktionierten die Änderungen in der Statusleiste wie erwartet ordnungsgemäß (und die preferredStatusBarStyleMethode 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 (veraltet in iOS 9)

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

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];

oder

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];

Beachten Sie, dass Sie auch Set benötigen , UIViewControllerBasedStatusBarAppearanceum NOin der plist - Datei , wenn Sie diese Methode verwenden.

AbdullahC
quelle
2
Ich habe das gleiche Problem wie Sie und den Root-View-Controller nicht eingestellt. Wie zum Teufel hast du das gefunden?
Trgoofi
1
Ich hatte den Verdacht, dass etwas im Framework nicht benachrichtigt wurde setNeedsStatusBarAppearanceUpdate- mein Verdacht wurde bestätigt, als ich diese Änderung vornahm.
AbdullahC
2
Ein verwandtes Problem, das ich in einer App gefunden habe, war ein Ansichts-Controller mit einem untergeordneten Vollbild-Ansichts-Controller, der childViewControllerForStatusBarStyle und childViewControllerForStatusBarHidden nicht überschrieb, um diesen untergeordneten Ansichts-Controller zurückzugeben. Wenn Sie über eine eigene View Controller-Hierarchie verfügen, müssen Sie diese Methoden bereitstellen, um das System darüber zu informieren, welcher View Controller zur Bestimmung des Statusleistenstils verwendet werden soll.
Jon Steinmetz
Das Einstellen des Rootviewcontrollers ändert nichts. Sie sollten mit dem Kommentar von Jon arbeiten. Und seien Sie vorsichtig, wenn Sie setneedsstatusbarappearanceUpdate aufrufen. Sie sollten es vom Elternteil aufrufen, um zu arbeiten.
DoozMen
1
@ Hippo du bist genial !! Wie haben Sie festgestellt, dass der Rootviewcontroller nicht eingestellt wurde?
ViruMax
1019

Für alle, die einen UINavigationController verwenden:

Der UINavigationControllerleitet keine preferredStatusBarStyleAnrufe an seine untergeordneten Ansichtscontroller weiter. Stattdessen verwaltet es seinen eigenen Status - wie es sollte, zeichnet es am oberen Bildschirmrand, wo sich die Statusleiste befindet, und sollte daher dafür verantwortlich sein. Daher wird die Implementierung preferredStatusBarStylein Ihren VCs innerhalb eines Navigationscontrollers nichts bewirken - sie werden niemals aufgerufen.

Der Trick ist, was die UINavigationControllerverwendet, um zu entscheiden, was für UIStatusBarStyleDefaultoder zurückgegeben werden soll UIStatusBarStyleLightContent. Es stützt dies auf seine UINavigationBar.barStyle. Das default ( UIBarStyleDefault) führt zur dunklen Vordergrundstatusleiste UIStatusBarStyleDefault. Und UIBarStyleBlackgibt eine UIStatusBarStyleLightContentStatusleiste.

TL; DR:

Wenn Sie UIStatusBarStyleLightContenteine UINavigationControllerVerwendung wünschen :

self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
Tyson
quelle
59
Nett! Beachten Sie, dass dies preferredStatusBarStyletatsächlich auf dem untergeordneten Ansichtscontroller aufgerufen wird, wenn Sie die Navigationsleiste ( navigationBarHiddenauf YES) genau entsprechend ausblenden .
Patrick Pijnappel
25
Danke für diese Antwort. Wenn Sie den barStyle für alle Ihre Navigationsleisten festlegen möchten, rufen Sie[[UINavigationBar appearance] setBarStyle:UIBarStyleBlack]
Thomas Desert
15
Perfekte Antwort. Keine der anderen Antworten auf SO berücksichtigte den UINavigationController. 2 Stunden meinen Kopf gegen die Tastatur schlagen.
Ryan Alford
10
Ein großes Lob an @Patrick für die Angabe, dass navigationBarHiddenset to YEStatsächlich preferredStatusBarStyleangerufen hat, und eine Warnung an diejenigen, die darüber stolpern könnten: Es funktioniert mit navigationBarHidden, aber nicht mit navigationBar.hidden!
JCaron
4
sollte offensichtlich sein, aber Sie müssen auch "View controller-based status bar display" in Info.plist auf YES setzen, damit dies funktioniert.
Code Baller
99

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

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

und ließ diese den aktuell sichtbaren UIViewController zurückgeben. Auf diese Weise kann der aktuelle Controller für sichtbare Ansichten seinen eigenen bevorzugten Stil / Sichtbarkeit festlegen.

Hier ist ein vollständiger Code-Ausschnitt dafür:

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

Stellen Sie schließlich sicher, dass in Ihrer App-Liste NICHT die Option "Controller-basiertes Statusleisten-Erscheinungsbild anzeigen" auf NEIN gesetzt ist. Löschen Sie diese Zeile oder setzen Sie sie auf YES (was ist meiner Meinung nach jetzt die Standardeinstellung für iOS 7?)

serenn
quelle
Sieht aus wie return self.topViewController;funktioniert für mich, aber return self.visibleViewController;- nicht
k06a
VisualViewController kann den aktuell präsentierten Modal Controller zurückgeben, wenn Sie ihn schließen. Welches ist Mist. Verwenden Sie topViewController.
Ben Sinclair
1
@ d.lebedev ok, aber ich denke, keines dieser Probleme trifft hier zu. Sie müssen nicht anrufen müssen superin dieser Methode , und Sie wollen tatsächlich das Verhalten aller Controller dieser Art zu ändern
ed‘
1
Dies funktioniert bei iOS 9.3 nicht. Ich denke, das ist das Problem: Dieses Problem ist von besonderer Bedeutung, da viele der Cocoa-Klassen mithilfe von Kategorien implementiert werden. Eine vom Framework definierte Methode, die Sie überschreiben möchten, wurde möglicherweise selbst in einer Kategorie implementiert. Daher ist nicht definiert, welche Implementierung Vorrang hat.
Vikingosegundo
2
Dies ist falsch und es bricht in iOS 13.4. Weil die Erweiterung der Ziel-C-Klassen in Swift über Ziel-C-Kategorien implementiert wird. Das Überschreiben von Methoden durch Ziel-C-Kategorien wird nicht empfohlen und ist wahrscheinlich fehlerhaft. Siehe stackoverflow.com/a/38274660/2438634
Marc Etcheverry
79

Für alle, die immer noch damit zu kämpfen haben, sollte diese einfache Erweiterung in Swift das Problem für Sie beheben.

extension UINavigationController {
    override open var childForStatusBarStyle: UIViewController? {
        return self.topViewController
    }
}
Alex Brown
quelle
10
Sie, mein Herr, verdienen eine Medaille.
Nikans
2
Vielen Dank Mann. Ich habe stattdessen sichtbarViewController ohne Erfolg zurückgegeben.
Fábio Salata
1
Das ist Gold. Ich habe einen Navigationscontroller in eine Registerkartenleiste eingebettet und habe diesen einfach in eine Datei geworfen. Jetzt kann ich das Erscheinungsbild der Statusleiste an einer beliebigen Stelle ändern.
Vahid Amiri
2
Dies ist falsch und es bricht in iOS 13.4. Weil die Erweiterung der Ziel-C-Klassen in Swift über Ziel-C-Kategorien implementiert wird. Das Überschreiben von Methoden durch Ziel-C-Kategorien wird nicht empfohlen und ist wahrscheinlich fehlerhaft. Siehe stackoverflow.com/a/38274660/2438634
Marc Etcheverry
1
@MarcEtcheverry diese bestimmte Instanz war nicht falsch. Tatsache ist, dass die Unterklassen anderer Objekte / Protokolle wie UINavigationController keine vorherige Implementierung hatten, um Konflikte beim dynamischen Versand zu verursachen. Es gab keine Standardeinstellungen oder Implementierungen innerhalb der tatsächlichen Unterklassen, weshalb dies der sauberste Weg war, dies in einer App zu implementieren, ohne eine unnötige Abhängigkeit (Punkt) zu erzeugen. Leider scheint 13.4 dieses Verhalten geändert zu haben. Ich vermute hinter den Kulissen, dass sie jetzt eine Überprüfung oder Implementierung haben, die es seit Jahren nicht mehr gibt .........
TheCodingArt
20

Meine app verwendet , um alle drei: UINavigationController, UISplitViewController, UITabBarController, damit alle diese scheinen die Kontrolle über die Statusleiste zu übernehmen und wird dazu führen , preferedStatusBarStylenicht für ihre Kinder heißen. 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, Apple wäre klarer über diese Art von Dingen.

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

Bearbeiten: Update für Swift 4.2 API-Änderungen

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

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

extension UITabBarController {
    open override var childForStatusBarStyle: UIViewController? {
        return self.children.first
    }

    open override var childForStatusBarHidden: UIViewController? {
        return self.children.first
    }
}

extension UISplitViewController {
    open override var childForStatusBarStyle: UIViewController? {
        return self.children.first
    }

    open override var childForStatusBarHidden: UIViewController? {
        return self.children.first
    }
}
Luis
quelle
1
Dies ist die einzige Lösung, die funktioniert. Alle Antworten auf SO verweisen auf die Standardlösung, die für keine App mit NavigationControllern funktioniert. Danke dir!!!
Houman
Die Verwendung von Erweiterungen zum Überschreiben ist einfach falsch. Das ist nicht sicher. Es gibt mehrere einfachere Lösungen. Verwenden Sie stattdessen eine Unterklasse.
Sulthan
2
Dies ist falsch und es bricht in iOS 13.4. Weil die Erweiterung der Ziel-C-Klassen in Swift über Ziel-C-Kategorien implementiert wird. Das Überschreiben von Methoden durch Ziel-C-Kategorien wird nicht empfohlen und ist wahrscheinlich fehlerhaft. Siehe stackoverflow.com/a/38274660/2438634
Marc Etcheverry
1
@MarcEtcheverry diese bestimmte Instanz war nicht falsch. Tatsache ist, dass die Unterklassen anderer Objekte / Protokolle wie UINavigationController keine vorherige Implementierung hatten, um Konflikte beim dynamischen Versand zu verursachen. Es gab keine Standardeinstellungen oder Implementierungen innerhalb der tatsächlichen Unterklassen, weshalb dies der sauberste Weg war, dies in einer App zu implementieren, ohne eine unnötige Abhängigkeit (Punkt) zu erzeugen. Leider scheint 13.4 dieses Verhalten geändert zu haben. Ich vermute hinter den Kulissen, dass sie jetzt eine Überprüfung oder Implementierung haben, die es seit Jahren nicht mehr gibt .........
TheCodingArt
15

Tysons Antwort ist richtig, wenn die Farbe der Statusleiste in Weiß geändert wird UINavigationController.

Wenn jemand das gleiche Ergebnis erzielen möchte, indem er den Code schreibt, AppDelegateverwenden Sie den folgenden Code und schreiben Sie ihn in die AppDelegate's didFinishLaunchingWithOptionsMethode.

Und vergessen Sie nicht , die zu setzen , UIViewControllerBasedStatusBarAppearanceum YESin der .plist - Datei, sonst wird die Änderung nicht widerspiegeln.

Code

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

     return YES;
}
Yogesh Suthar
quelle
14

Wird auf einem UINavigationController preferredStatusBarStylenicht aufgerufen, da dies topViewControllerbevorzugt wird self. Um preferredStatusBarStyleauf einem UINavigationController aufgerufen zu werden, müssen Sie dessen ändern childViewControllerForStatusBarStyle.

Empfehlung

Überschreiben Sie Ihren UINavigationController in Ihrer Klasse:

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

Nicht empfohlene Alternative

Um dies für alle UINavigationController zu tun, können Sie eine Erweiterung überschreiben (Warnung: Dies betrifft UIDocumentPickerViewController, UIImagePickerController usw.), aber Sie sollten dies wahrscheinlich nicht gemäß der Swift-Dokumentation tun :

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

Wenn Sie einen Ansichts-Controller mit einem modalPresentationStyle(zum Beispiel .overCurrentContext) präsentieren, sollten Sie zusätzlich zur Antwort von serenn dies auch auf dem neu präsentierten Ansichts-Controller aufrufen:

presentedViewController.modalPresentationCapturesStatusBarAppearance = true

Vergessen Sie nicht, auch den preferredStatusBarStyleim dargestellten View Controller überschriebenen zu überschreiben .

frin
quelle
9

Eine Ergänzung 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 die Umstellung auf ein bald veraltetes Verhalten.

Artem Abramov
quelle
Tun Sie dies nicht, es funktioniert vorerst, kann aber das zukünftige Verhalten beeinträchtigen. Ändern Sie einfach den navBar-Stil - siehe meine Antwort stackoverflow.com/a/19513714/505457
Tyson
2
Sie sollten eine Unterklasse verwenden, keine Kategorie.
Shuiyouren
2Tyson: Warum wird es zukünftiges Verhalten brechen? PreferredStatusBarStyle: Dies ist die bevorzugte Methode von Apple zum Einrichten des Statusleistenstils.
Artem Abramov
2shuiyouren: Warum sollte ich die Komplexität durch Unterklassen erhöhen, wenn ich nur eine Kategorie verwenden und sie an jedem Ort einfügen kann, an dem ich möchte? Wie auch immer, das ist eine Frage der Architektur, nicht der Implementierung.
Artem Abramov
2
@ArtemAbramov Da der UINavigationController bereits eine preferredStatusBarStyleUINavigationController-spezifische Logik implementiert und ausführt. Im Moment basiert diese Logik auf, navigationBar.barStyleaber ich kann sehen, dass zusätzliche Überprüfungen hinzugefügt werden (z. B. UISearchDisplayControllerBewegen, um den Navigationsleistenmodus auszublenden). Wenn Sie die Standardlogik überschreiben, verlieren Sie all diese Funktionen und lassen sich für nervige 'wtf'-Momente in der Zukunft offen. In meiner Antwort oben finden Sie die richtige Vorgehensweise, während das Verhalten des integrierten Navigationscontrollers weiterhin unterstützt wird.
Tyson
9

Swift 4.2 und höher

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

Mögliche Fälle Ihrer Flussstruktur

  • Benutzerdefiniertes UIViewController-Objekt ist ein Fensterstamm-Ansichts-Controller.

    Ihr Fensterstamm-Ansichts-Controller ist ein UIViewController-Objekt und fügt basierend auf Ihrem Anwendungsfluss einen Navigations-Controller oder tabController hinzu oder entfernt ihn.

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

  • TabBarController-Objekt ist Window Root View Controller

    Dies ist der Ablauf, in dem Window Root View Controller TabBarController ist. Möglicherweise enthält jede Registerkarte den Navigationscontroller.

  • Das NavigationController-Objekt ist der Fensterstammansicht-Controller.

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

    Ich bin nicht sicher, ob es eine Möglichkeit gibt, einen Registerkartenleisten-Controller oder einen neuen Navigations-Controller in einen vorhandenen Navigations-Controller einzufügen. In diesem Fall müssen wir jedoch das Steuerelement für den Statusleistenstil an den nächsten Container übergeben. Also habe ich die gleiche Prüfung in der UINavigationController-Erweiterung hinzugefügt, um sie zu findenchildForStatusBarStyle

Verwenden Sie die folgenden Erweiterungen, um alle oben genannten Szenarien zu behandeln :

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 brauchen keine UIViewControllerBasedStatusBarAppearanceSchlüssel in info.plistwie es wahr standardmäßig

Zu berücksichtigende Punkte für komplexere Abläufe

  • Wenn Sie einen neuen Flow modal präsentieren, wird er vom vorhandenen Flow im Statusleistenstil getrennt. Angenommen, Sie präsentieren einen NewFlowUIViewControllerund fügen dann einen neuen Navigations- oder TabBar-Controller hinzu. Fügen Sie NewFlowUIViewControllerdann auch eine Erweiterung von hinzu NewFlowUIViewController, um den Statusleistenstil des weiteren Ansichts-Controllers zu verwalten.

  • Wenn Sie modalPresentationStyle anders als fullScreenbei der modalen Präsentation festlegen, müssen Sie modalPresentationCapturesStatusBarAppearancetrue festlegen , damit der Controller für die präsentierte Ansicht die Statussteuerung für das Erscheinungsbild erhält.

abhimanyu jindal
quelle
Hervorragende Antwort!
Amin Benarieb
3
Dies ist falsch und es bricht in iOS 13.4. Weil die Erweiterung der Ziel-C-Klassen in Swift über Ziel-C-Kategorien implementiert wird. Das Überschreiben von Methoden durch Ziel-C-Kategorien wird nicht empfohlen und ist wahrscheinlich fehlerhaft. Siehe stackoverflow.com/a/38274660/2438634
Marc Etcheverry
@MarcEtcheverry diese bestimmte Instanz war nicht falsch. Tatsache ist, dass die Unterklassen anderer Objekte / Protokolle wie UINavigationController keine vorherige Implementierung hatten, um Konflikte beim dynamischen Versand zu verursachen. Es gab keine Standardeinstellungen oder Implementierungen innerhalb der tatsächlichen Unterklassen, weshalb dies der sauberste Weg war, dies in einer App zu implementieren, ohne eine unnötige Abhängigkeit (Punkt) zu erzeugen. Leider scheint 13.4 dieses Verhalten geändert zu haben. Ich vermute hinter den Kulissen, dass sie jetzt eine Überprüfung oder Implementierung haben, die es seit Jahren nicht mehr gibt .........
TheCodingArt
8

iOS 13 Lösung (en)

UINavigationControllerist eine Unterklasse von UIViewController(wer wusste 🙃)!

Wenn Sie in Navigationscontrollern eingebettete Ansichtscontroller präsentieren, präsentieren Sie die eingebetteten Ansichtscontroller daher nicht wirklich. Sie präsentieren die Navigationssteuerungen! UINavigationController, als Unterklasse von UIViewController, erbt preferredStatusBarStyleundchildForStatusBarStyle , die Sie nach Wunsch einstellen können.

Jede der folgenden Methoden sollte funktionieren:

  1. Deaktivieren Sie den dunklen Modus vollständig
    • In deinem info.plist die folgende Eigenschaft hinzu:
      • Schlüssel - UIUserInterfaceStyle (auch bekannt als "User Interface Style")
      • Wert - Licht
  2. preferredStatusBarStyleInnerhalb überschreibenUINavigationController

    • preferredStatusBarStyle( doc ) - Der bevorzugte Statusleistenstil für den Ansichtscontroller
    • Unterklasse oder erweitern UINavigationController

      class MyNavigationController: UINavigationController {
          override var preferredStatusBarStyle: UIStatusBarStyle {
              .lightContent
          }
      }

      ODER

      extension UINavigationController {
          open override var preferredStatusBarStyle: UIStatusBarStyle {
              .lightContent
          }
      }
  3. childForStatusBarStyleInnerhalb überschreibenUINavigationController

    • childForStatusBarStyle( doc ) - Wird aufgerufen, wenn das System den Ansichtscontroller zur Bestimmung des Statusleistenstils benötigt
    • Laut Apples Dokumentation

      "Wenn Ihr Container-Ansichts-Controller seinen Statusleistenstil von einem seiner untergeordneten Ansichts-Controller ableitet, [überschreiben Sie diese Eigenschaft] und geben Sie diesen untergeordneten Ansichts-Controller zurück. Wenn Sie null zurückgeben oder diese Methode nicht überschreiben, wird der Statusleistenstil für self verwendet Wenn sich der Rückgabewert dieser Methode ändert, rufen Sie die Methode setNeedsStatusBarAppearanceUpdate () auf. "

    • Mit anderen Worten, wenn Sie Lösung 3 hier nicht implementieren, greift das System auf Lösung 2 oben zurück.
    • Unterklasse oder erweitern UINavigationController

      class MyNavigationController: UINavigationController {
          override var childForStatusBarStyle: UIViewController? {
              topViewController
          }
      }

      ODER

      extension UINavigationController {    
          open override var childForStatusBarStyle: UIViewController? {
              topViewController
          }
      }
    • Sie können jeden View Controller zurückgeben, den Sie oben möchten. Ich empfehle eine der folgenden Möglichkeiten:

      • topViewController(of UINavigationController) ( doc ) - Der Ansichts-Controller oben im Navigationsstapel
      • visibleViewController(of UINavigationController) ( doc ) - Der Ansichtscontroller, der der aktuell sichtbaren Ansicht in der Navigationsoberfläche zugeordnet ist (Hinweis: Dies kann "einen Ansichtscontroller umfassen, der modal über dem Navigationscontroller selbst dargestellt wurde").

Hinweis: Wenn Sie sich für eine Unterklasse entscheiden UINavigationController, denken Sie daran, diese Klasse über den Identitätsinspektor in IB auf Ihre Navigationssteuerungen anzuwenden.

PS Mein Code verwendet die Swift 5.1-Syntax 😎

Andrew Kirna
quelle
Meine Statusleiste wird nach der Bildschirmdrehung schwarz. Irgendeine Idee warum? Dies geschieht nur auf dem iPad Pro Simulator.
Pedro Paulo Amorim
@PedroPauloAmorim, können Sie weitere Informationen bereitstellen? Wie wird der Top View Controller dargestellt (modal, Vollbild, Show)? Ist es in einem Navigationscontroller verschachtelt? Wird der Text schwarz oder auch der Hintergrund? Was versuchst du zu erreichen?
Andrew Kirna
Ich habe die Lichtstatusleiste in meiner gesamten App festgelegt. Es wird in zwei Umdrehungen hell, in der dritten wird es dunkel und kehrt nie zum Licht zurück, selbst wenn es gezwungen wird, es neu zu zeichnen. Es passiert auf dem iPad Pro Simulator. Die Ansichten werden im Vollbildmodus angezeigt und sind nicht in einem Navigationscontroller verschachtelt. Nur der Text wird dunkel.
Pedro Paulo Amorim
Wie stellen Sie die Lichtstatusleiste überhaupt ein?
Andrew Kirna
3
Ihr Überschreiben über die Erweiterung ist keine echte Überschreibung. Es ist ein unsicherer Missbrauch der Sprache. Das kann sehr leicht brechen.
Sulthan
7

Die Antwort von @ serenn oben ist für den Fall von UINavigationControllers immer noch großartig. Für Swift 3 wurden jedoch die childViewController-Funktionen in geändert vars. Der UINavigationControllerErweiterungscode 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 soll:

override var preferredStatusBarStyle: UIStatusBarStyle {
   return .lightContent
}
John Stricker
quelle
2
Dies ist falsch und es bricht in iOS 13.4. Weil die Erweiterung der Ziel-C-Klassen in Swift über Ziel-C-Kategorien implementiert wird. Das Überschreiben von Methoden durch Ziel-C-Kategorien wird nicht empfohlen und ist wahrscheinlich fehlerhaft. Siehe stackoverflow.com/a/38274660/2438634
Marc Etcheverry
@MarcEtcheverry diese bestimmte Instanz war nicht falsch. Tatsache ist, dass die Unterklassen anderer Objekte / Protokolle wie UINavigationController keine vorherige Implementierung hatten, um Konflikte beim dynamischen Versand zu verursachen. Es gab keine Standardeinstellungen oder Implementierungen innerhalb der tatsächlichen Unterklassen, weshalb dies der sauberste Weg war, dies in einer App zu implementieren, ohne eine unnötige Abhängigkeit (Punkt) zu erzeugen. Leider scheint 13.4 dieses Verhalten geändert zu haben. Ich vermute hinter den Kulissen, dass sie jetzt eine Überprüfung oder Implementierung haben, die es seit Jahren nicht mehr gibt .........
TheCodingArt
6

Wenn sich Ihr viewController unter UINavigationController befindet.

Unterklasse UINavigationController und hinzufügen

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

ViewController preferredStatusBarStylewird aufgerufen.

PowHu
quelle
4

UIStatusBarStyle in iOS 7

Die Statusleiste in iOS 7 ist transparent, die Ansicht dahinter 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). Beide UIStatusBarStyleBlackTranslucentund UIStatusBarStyleBlackOpaquesind in iOS 7.0 veraltet. Verwenden Sie UIStatusBarStyleLightContentstattdessen.

Wie man sich ändert UIStatusBarStyle

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

Wenn der Navigationsleistenstil UIBarStyleDefault ist, lautet der Statusleistenstil UIStatusBarStyleDefault. Wenn der Navigationsleistenstil ist UIBarStyleBlack, ist der Statusleistenstil UIStatusBarStyleLightContent.

Befindet sich unterhalb der Statusleiste keine Navigationsleiste, kann der Stil der Statusleiste von einem einzelnen Ansichts-Controller gesteuert und geändert werden, während die App ausgeführt wird.

- [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 von einem untergeordneten Ansichtscontroller anstelle von self gesteuert werden soll, überschreiben Sie ihn -[UIViewController childViewControllerForStatusBarStyle], um diesen untergeordneten Ansichtscontroller zurückzugeben.

Wenn Sie dieses Verhalten lieber deaktivieren und den Statusleistenstil mithilfe der -[UIApplication statusBarStyle]Methode festlegen möchten , fügen Sie den UIViewControllerBasedStatusBarAppearanceSchlüssel zur Info.plistDatei einer App hinzu und geben Sie den Wert NO ein.

oscarr
quelle
3

Wenn jemand einen Navigationscontroller verwendet und möchte, dass alle Navigationscontroller den schwarzen Stil haben, können Sie in Swift 3 eine Erweiterung zu UINavigationController wie diese schreiben, die für alle Navigationscontroller gilt (anstatt sie einem Controller an einem zuzuweisen Zeit).

extension UINavigationController {

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

        self.navigationBar.barStyle = UIBarStyle.black
    }

}
Benjamin Lowry
quelle
1
Aber was ist, wenn meine Navigationsleiste ausgeblendet ist?
Slavcho
1
Weil die Navigation ausgeblendet und die Statusleiste sichtbar sein muss.
Slavcho
1

In Swift für jede Art von UIViewController:

In Ihrem AppDelegateSet:

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

myRootControllerkann jede Art von sein UIViewController, zB UITabBarControlleroder UINavigationController.

Überschreiben Sie dann diesen Root-Controller wie folgt:

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

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

Denken Sie daran, die Eigenschaft View controller-based status bar appearancein Ihrem auf YES Info.plistzu setzen, damit dies funktioniert (dies ist die Standardeinstellung).

Verdammt
quelle
@Wie geht das in swift3?
Flugzeug
1

Swift 3 iOS 10 Lösung:

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

Die meisten Antworten enthalten keine gute Implementierung der childViewControllerForStatusBarStyleMethode für UINavigationController. Nach meiner Erfahrung sollten Sie solche Fälle behandeln, in denen der transparente Ansichtscontroller über dem Navigationscontroller angezeigt wird. In diesen Fällen sollten Sie die Steuerung an Ihren Modal Controller ( visibleViewController) übergeben, jedoch nicht, wenn dieser verschwindet.

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

In meinem Fall habe ich versehentlich den View / Navigation Controller als dargestellt UIModalPresentationStyle.overFullScreen, was dazu führt, dass preferredStatusBarStylenicht aufgerufen wird. Nach dem Zurückschalten UIModalPresentationStyle.fullScreenfunktioniert alles.

Casey
quelle
1

Da für iOS 13.4 die preferredStatusBarStyleMethode in der UINavigationControllerKategorie nicht aufgerufen wird, scheint Swizzling die einzige Option zu sein, ohne dass eine Unterklasse verwendet werden muss.

Beispiel:

Kategorie-Header:

@interface UINavigationController (StatusBarStyle)
+ (void)setUseLightStatusBarStyle;
@end

Implementierung:

#import "UINavigationController+StatusBarStyle.h"
#import <objc/runtime.h>

@implementation UINavigationController (StatusBarStyle)

void (^swizzle)(Class, SEL, SEL) = ^(Class c, SEL orig, SEL new){
    Method origMethod = class_getInstanceMethod(c, orig);
    Method newMethod = class_getInstanceMethod(c, new);
    if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
        class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
    else
        method_exchangeImplementations(origMethod, newMethod);
};

+ (void)setUseLightStatusBarStyle {
    swizzle(self.class, @selector(preferredStatusBarStyle), @selector(_light_preferredStatusBarStyle));
}

- (UIStatusBarStyle)_light_preferredStatusBarStyle {
    return UIStatusBarStyleLightContent;
}    
@end

Verwendung in AppDelegate.h:

#import "UINavigationController+StatusBarStyle.h"

[UINavigationController setUseLightStatusBarStyle];
Kevin Flachsmann
quelle
0

Hier ist meine Methode, um 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 in UIViewController eine Kategorie namens 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

Jetzt ist es an der Zeit zu sagen, dass Ihr View Controller das AGViewControllerAppearance- Protokoll implementiert .

Beispiel:

@interface XYSampleViewController () <AGViewControllerAppearance>

... the rest of the interface

@end

Natürlich können Sie den Rest der Verfahren (Umsetzung showsStatusBar , animatesStatusBarVisibility , prefferedStatusBarAnimation ) aus dem Protokoll und UIViewController + Upgrade - tun die Anpassung richtige auf der Grundlage der von ihnen gelieferten Werte.

Arturgrigor
quelle
0

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

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

Beachten Sie dies bei Verwendung der self.navigationController.navigationBar.barStyle = UIBarStyleBlack;Lösung

Stellen Sie sicher, dass Sie zu Ihrer Liste gehen und "Erscheinungsbild der Controller-basierten Statusleiste anzeigen" auf JA setzen. Wenn es NEIN ist, wird es nicht funktionieren.

Richard Garfield
quelle
Das Setzen von UIViewControllerBasedStatusBarAppearance auf YES in der Projektliste machte den Unterschied für mich aus. Ich hatte es vergessen.
Filo
0

Seit Xcode 11.4 überschreiben die preferredStatusBarStyle funktioniert das Eigenschaft in einer UINavigationController-Erweiterung nicht mehr, da sie nicht aufgerufen wird.

Das Einstellen barStylevon navigationBarauf .blackfunktioniert zwar, dies führt jedoch zu unerwünschten Nebenwirkungen, wenn Sie der Navigationsleiste Unteransichten hinzufügen, die für den Hell- und Dunkelmodus möglicherweise unterschiedlich aussehen. Denn wenn Sie die Option barStyleauf Schwarz setzen, wird die userInterfaceStyleAnsicht, die in die Navigationsleiste eingebettet ist, immer userInterfaceStyle.darkunabhängig userInterfaceStylevon der App angezeigt .

Die richtige Lösung, die ich finde, besteht darin, eine Unterklasse von hinzuzufügen UINavigationControllerund dort zu überschreiben preferredStatusBarStyle. Wenn Sie dann diesen benutzerdefinierten UINavigationController für alle Ihre Ansichten verwenden, befinden Sie sich auf der Speicherseite.

PatrickDotStar
quelle
-1

Der NavigationController oder der TabBarController sind diejenigen, die den Stil bereitstellen müssen. Hier ist, wie ich gelöst habe: https://stackoverflow.com/a/39072526/242769

aryaxt
quelle
Wenn Sie denken, dass dies ein Duplikat einer anderen Frage ist, schließen Sie die Abstimmung bitte als Duplikat ab