UIStatusBarStyle PreferredStatusBarStyle non funziona su iOS 7


110

Nella mia applicazione iPhone costruita con Xcode 5 per iOS 7 I set UIViewControllerBasedStatusBarAppearance=YESin info.plist, e nel mio ViewControllerho questo codice:

-(UIStatusBarStyle) preferredStatusBarStyle
{
    return UIStatusBarStyleLightContent;
}

Ma la barra di stato è ancora nera su sfondo nero.

So che la sua possibile cambiare questa applicazione a livello impostando UIViewControllerBasedStatusBarAppearance=NOin info.plist, ma in realtà ho bisogno di modificare questo su una viewControllerda viewControllerbasi in fase di esecuzione.


Ciao, ho lo stesso problema che hai menzionato in questione. Hai trovato la soluzione? Per favore, me lo fornisca.
Noundla Sandeep

Risposte:


281

Ho scoperto che se il tuo ViewController è all'interno di un navigationController, il navigationController navigationBar.barStyledetermina lo statusBarStyle.

L'impostazione della barra di navigazione barStylesu UIBarStyleBlackTranslucentfornirà un testo bianco (es. UIStatusBarStyleLightContent) Alla barra di stato e un testo UIBarStyleDefaultnero (es. UIStatusBarStyleDefault).

Nota che questo vale anche se cambi totalmente il colore della navigationBar tramite il suo barTintColor.


questo ha senso per me ... fantastico
Nick

14
Credo che sia perché il UINavigationController's preferredStatusBarStylenon chiama attraverso il ViewController che ospita, e invece ritorna semplicemente in base al suo navigationBarStyle.
mxcl

In questo caso la visualizzazione non è all'interno di un controller di navigazione.
Andrew Smith

Molto controintuitivo pensare che lo stile della barra abbia la preferenza su un metodo implementato nel controller di visualizzazione e solo quando si presentano visualizzazioni modali!
Matej

3
UIBarStyleBlackTranslucent è deprecato, usa UIBarStyleBlackinvece
Nhon Nguyen

87

OK, ecco il trucco. È necessario aggiungere la chiave "Visualizza barra di stato basata su controller" e impostare il valore su No.

Questo è in contrasto con quello che sembra il significato di questa chiave, ma anche se si imposta il valore su No, è comunque possibile modificare l'aspetto della barra di stato e se viene visualizzata o meno in qualsiasi controller di visualizzazione. Quindi si comporta come "Sì" ma impostalo su "No"!

Ora posso ottenere la barra di stato bianca o scura.


6
Per me questo era sbagliato. La chiave doveva essere impostata su "Sì", come ci si aspetterebbe. Sono su Xcode 5.1 iOS 7.1, quindi forse è cambiato.
joel.d

Sto usando Xcode 5.1 e iOS 7.1 e NO ha funzionato per me ... STRANO.
Arjun Mehta

Dove devo aggiungere questa chiave?
Hadu

Nel file [AppName] -Info.plist
Saren Inden

1
Funziona bene quando il tasto "Visualizza barra di stato basata su controller" è impostato su "SÌ" con Xcode6.0, iOS 8.0
bpolat

77

Per preferredStatusBarStyle()lavorare all'interno UINavigationControllere UITabBarControlleraggiungo il seguente codice, che otterrà lo stile della barra di stato preferito dal controller di visualizzazione attualmente visibile.

extension UITabBarController {
    public override func childViewControllerForStatusBarStyle() -> UIViewController? {
        return selectedViewController
    }
}

extension UINavigationController {
    public override func childViewControllerForStatusBarStyle() -> UIViewController? {
        return visibleViewController
    }
}

Per Swift 3 questi non sono metodi ma proprietà:

extension UITabBarController {
    open override var childViewControllerForStatusBarStyle: UIViewController? {
        return selectedViewController
    }
}

extension UINavigationController {
    open override var childViewControllerForStatusBarStyle: UIViewController? {
        return visibleViewController
    }
}

Le proprietà di Swift 4.2 sono state rinominate:

extension UITabBarController {
   open override var childForStatusBarStyle: UIViewController? {
        return selectedViewController
    }
}

extension UINavigationController {
   open override var childForStatusBarStyle: UIViewController? {
        return visibleViewController
    }
}

uso

class ViewController: UIViewController {

    // This will be called every time the ViewController appears
    // Works great for pushing & popping
    override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }

}

6
Questa è di gran lunga la risposta migliore (per le app che utilizzano UINavigationController o UITabBarController
Kesava

1
qual è l'uso per questo?
AnBisw

@Annjawn questi metodi sono usati da UIKit. Non devi fare altro che aggiungerlo al tuo progetto.
Daniel Wood

@DanielWood sì, l'ho capito e ho completamente dimenticato di aver usato esattamente la stessa cosa in uno dei miei progetti precedenti, anche se in modo leggermente diverso.
AnBisw

Questa è davvero la risposta migliore
Musa almatri

33

Potrei arrivare a questo un po 'in ritardo, ma nel caso qualcun altro stia cercando una soluzione valida e verificata per l'app.

@mxcl è corretto nel descrivere il motivo per cui sta accadendo. Per correggerlo, creiamo semplicemente un'estensione (o una categoria in obj-c) che sovrascrive il metodo preferredSatusBarStyle () di UINavigationController. Ecco un esempio in Swift:

extension UINavigationController {
    public override func preferredStatusBarStyle() -> UIStatusBarStyle {
        if let rootViewController = self.viewControllers.first {
            return rootViewController.preferredStatusBarStyle()
        }
        return super.preferredStatusBarStyle()
    }
}

Questo codice estrae semplicemente il primo controller di visualizzazione (il controller di visualizzazione root) e lo decomprime (in obj-c basta controllare che non sia nullo). Se lo scartamento ha esito positivo (non nullo), prendiamo il rootViewControllers preferredStatusBarStyle. Altrimenti restituiamo semplicemente il valore predefinito.

Spero che questo aiuti chiunque ne abbia bisogno.


2
In Swift 2.0 è necessario rimuovere "as? UIViewController" dall'istruzione della condizione.
Thomás Calmon

Fantastico, ho apportato una modifica oltre a rimuovere l'istruzione "as", l'ho cambiata da "primo" a "ultimo" in questo modo qualunque controller di visualizzazione viene visto dall'utente in cima allo stack avrà la capacità di controllare il colore della barra di stato. Lavoro fantastico, grazie per la condivisione!
Unome

1
Se il controller di navigazione non dispone di controller di visualizzazione, ciò causerebbe un ciclo infinito. return self.preferredStatusBarStyle()richiamerebbe in questo identico metodo.
BearMountain il

1
Nel mio caso, invece di usare rootViewController, ho usato topViewController poiché durante lo stack lo stile potrebbe cambiare.
Ric Santos

2
@Unome visibleViewControllersarebbe ancora meglio
Cœur

21

Per fornire maggiori dettagli nella risposta accettata, inserisci la seguente riga nel didFinishLaunchingWithOptions:metodo del delegato dell'app :

[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;

Quindi, nella tua Info.plist, aggiungilo View controller-based status bar appearancee impostalo suNO .

Credo che sia così che dovrebbe essere fatto, NON dal controller di navigazione, se si desidera lo stesso colore della barra di stato per l'intera app. Potresti avere schermate che non sono necessariamente incorporate in una UINavigationController, o una UINavigationControllersottoclasse diversa da qualche altra parte e altre cose.

MODIFICA : puoi anche farlo senza digitare alcun codice: https://stackoverflow.com/a/18732865/855680


1
Nota che questo modo è deprecato da IOS 9.0
Mohamed Salah

10

In viewDidLoad basta scrivere questo

[self setNeedsStatusBarAppearanceUpdate];

basta farlo e funzionerà

puoi provarlo per favore

Set UIViewControllerBasedStatusBarAppearance to NO.
Call [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];

Un'altra cosa che ho visto nella tua domanda è che hai scritto il metodo in questo modo

 -(void)UIStatusBarStyle PreferredStatusBarStyle ()
        {
            return UIStatusBarStyle.LightContent;
        }

ma dovrebbe essere così

-(UIStatusBarStyle)preferredStatusBarStyle{ 
    return UIStatusBarStyleLightContent; 
} 

Ciò causa la chiamata del metodo preferredStatusBarStyle, ma la barra di stato è ancora nera.
Andrew Smith

si prega di consultare la mia risposta aggiornata .. fammi sapere rapidamente se funziona o meno
Utente 1531343

La mia domanda originale dice esplicitamente che devo eseguire il controllo visualizzazione per visualizzazione della barra di stato.
Andrew Smith

puoi controllare il tuo codice con riferimento alla mia domanda aggiornata?
Utente 1531343

1
[self setNeedsStatusBarAppearanceUpdate];un ottimo metodo, grazie!
Supertecnoboff

6

Ecco come l'ho risolto. Di solito il navigationController o il tabBarController sono quelli che decidono l'aspetto della barra di stato (nascosto, colore, ecc.).

Quindi ho finito per creare una sottoclasse del controller di navigazione e sovrascrivere preferredStatusBarStyle. se il ViewContorller visibile corrente implementa StatusBarStyleHandler chiedo che il valore venga utilizzato come stile, in caso contrario restituisco solo un valore predefinito.

Il modo in cui si attiva un aggiornamento dell'aspetto della barra di stato è chiamando setNeedsStatusBarAppearanceUpdateche si attiva di preferredStatusBarStylenuovo e aggiorna l'interfaccia utente in base a ciò che restituisce il metodo

public protocol StatusBarStyleHandler {
    var preferredStatusBarStyle: UIStatusBarStyle { get }
}

public class CustomNavigationCotnroller: UINavigationController {

    public override var preferredStatusBarStyle: UIStatusBarStyle {
        if let statusBarHandler = visibleViewController as? StatusBarStyleHandler {
            return statusBarHandler.preferredStatusBarStyle
        }

        return .default
    }
}

Quindi l'utilizzo

public class SomeController: UIViewController, StatusBarStyleHandler {

    private var statusBarToggle = true

    // just a sample for toggling the status bar style each time method is called
    private func toggleStatusBarColor() {
        statusBarToggle = !statusBarToggle
        setNeedsStatusBarAppearanceUpdate()
    }

    public override var preferredStatusBarStyle: UIStatusBarStyle {
        return statusBarToggle ? .lightContent : .default
    }
}

Questo post sarebbe molto migliorato se tu potessi spiegare perché e come questo risolve il problema.

Invece di creare una sottoclasse di UINavigationController, puoi anche creare un'estensione per UINavigationController e ottenere lo stesso risultato senza dover creare una sottoclasse.
wilforeal

4

1) Un'impostazione per l'intero progetto:

Se disponibile, rimuovi la UIViewControllerBasedStatusBarAppearancecoppia chiave-valore dal tuo info.plist o imposta NOsenza rimuoverla. Se non è disponibile nel tuo info.plist, non fare nulla. L'impostazione predefinita èNO per questa proprietà.

Aggiungi sotto il codice al tuo AppDelegate.m:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
}

2) Impostazioni diverse per diversi controller di visualizzazione:

Aggiungi la UIViewControllerBasedStatusBarAppearancecoppia chiave-valore a info.plist e impostala suYES .

Se il tuo controller di visualizzazione non è integrato nel controller di navigazione. Diciamo MyViewController. aggiungi semplicemente il codice sotto al tuo file MyViewController.m. Se il tuo controller di visualizzazione è incorporato nel controller di navigazione, crea una nuova classe Cocoa Touch e rendila sottoclasse di UINavigationController. Diciamo MyNC. Seleziona Navigation Controller View sul tuo Storyboard, nel riquadro di destra; Utilità -> Ispettore identità -> Classe personalizzata -> Classe, digita "MyNC". Dopo aver collegato la visualizzazione Storyboard alla tua classe Cocoa Touch "MyNC", aggiungi il codice qui sotto a MyNC.m:

- (BOOL)prefersStatusBarHidden {
    return NO;
}

-(UIStatusBarStyle)preferredStatusBarStyle {
    return UIStatusBarStyleLightContent;
}

Sembra che in iOS9 UIViewControllerBasedStatusBarAppearance per impostazione predefinita contenga il valore YES, poiché dovevo aggiungerlo manualmente in .plist e impostarlo su NO per funzionare correttamente.
Mohd Asim,

4

Anche con tutte le risposte qui non ho ancora trovato la soluzione esatta per me, ma ho iniziato con la risposta di Daniel. Quello che ho ottenuto è stato:

override var preferredStatusBarStyle: UIStatusBarStyle {
     return visibleViewController?.preferredStatusBarStyle ?? .lightContent
}

nei controller di navigazione (simile per tab, solo selectedViewController). E poi rispetterà:

override var preferredStatusBarStyle: UIStatusBarStyle {
     return .lightContent
}

In ogni controller di visualizzazione a meno che non lo imposti diversamente. Non ho bisogno di chiamare da setNeedsStatusBarAppearanceUpdate()nessuna parte, si aggiorna solo quando arrivi a ciascun controller di visualizzazione.


2
Sono finito con la soluzione quasi identica dopo aver lottato per ore con questo.
Scott Jungwirth

Ad un certo punto questo sembra essere stato risolto, solo l'uso di preferredStatusBarStyle in ogni VC funziona bene per me ora.
Andrew Plummer

4

Soluzioni iOS 13

La risposta con il punteggio più alto utilizza il codice "legacy" 👎

L'impostazione della barStyleproprietà è ora (iOS 13+) considerata una "personalizzazione legacy". Secondo Apple ,

In iOS 13 e versioni successive, personalizza la barra di navigazione utilizzando le proprietà standardAppearance, compactAppearance e scrollEdgeAppearance. È possibile continuare a utilizzare queste funzioni di accesso precedenti per personalizzare direttamente l'aspetto della barra di navigazione, ma è necessario aggiornare personalmente l'aspetto per le diverse configurazioni della barra.

Per quanto riguarda il tuo tentativo - Eri sulla strada giusta!

UINavigationController è una sottoclasse di UIViewController (chi lo sapeva 🙃)!

Pertanto, quando si presentano i controller di visualizzazione incorporati nei controller di navigazione, in realtà non si presentano i controller di visualizzazione incorporati; stai presentando i controller di navigazione! UINavigationController, come sottoclasse di UIViewController, eredita preferredStatusBarStyleechildForStatusBarStyle , che è possibile impostare come desiderato.

Uno dei seguenti metodi dovrebbe funzionare:

  1. Sostituisci preferredStatusBarStyleall'internoUINavigationController

    • preferredStatusBarStyle( doc ) - Lo stile preferito della barra di stato per il controller della vista
    • Sottoclasse o estendi UINavigationController

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

      O

      extension UINavigationController {
          open override var preferredStatusBarStyle: UIStatusBarStyle {
              .lightContent
          }
      }
  2. Sostituisci childForStatusBarStyleall'internoUINavigationController

    • childForStatusBarStyle( doc ) - Chiamato quando il sistema richiede che il controller di visualizzazione utilizzi per determinare lo stile della barra di stato
    • Secondo la documentazione di Apple,

      "Se il controller della vista del contenitore deriva il suo stile della barra di stato da uno dei suoi controller della vista figlio, [sovrascrivi questa proprietà] e restituisci quel controller della vista figlio. Se restituisci zero o non sovrascrivi questo metodo, viene utilizzato lo stile della barra di stato per self . Se il valore restituito da questo metodo cambia, chiama il metodo setNeedsStatusBarAppearanceUpdate (). "

    • In altre parole, se non si implementa la soluzione 3 qui, il sistema tornerà alla soluzione 2 sopra.
    • Sottoclasse o estendi UINavigationController

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

      O

      extension UINavigationController {    
          open override var childForStatusBarStyle: UIViewController? {
              topViewController
          }
      }
    • Puoi restituire qualsiasi controller di visualizzazione che desideri sopra. Raccomando uno dei seguenti:

      • topViewController(of UINavigationController) ( doc ) - Il controller di visualizzazione nella parte superiore dello stack di navigazione
      • visibleViewController(di UINavigationController) ( doc ) - Il controller di visualizzazione associato alla visualizzazione attualmente visibile nell'interfaccia di navigazione (suggerimento: questo può includere "un controller di visualizzazione che è stato presentato in modo modale sopra il controller di navigazione stesso")

Nota: se decidi di creare una sottoclasse UINavigationController, ricorda di applicare quella classe ai controller di navigazione tramite l'ispettore di identità in IB.

PS Il mio codice utilizza la sintassi Swift 5.1 😎


1
Risposta molto completa, grazie! Inoltre, qualcosa che ho faticato per un po ', su iOS 13 lo .defaultstile prende in considerazione la modalità oscura e non è documentato, quindi se stai supportando anche le versioni precedenti di iOS puoi aggiungere if #available(iOS 13, *) { return .darkContent } else { return .default }se provi a impostare manualmente lo stile della barra di stato in base al colore dietro la barra di stato e quel colore è "luminoso".
valcanaia

1
Nota che il metodo di estensione per eseguire l'override var non funziona più in Xcode 11.4 / iOS 13.4
Marc Etcheverry

Perché l'estensione delle classi C obiettivo in Swift viene implementata tramite le categorie C obiettivo. L'override dei metodi attraverso le categorie dell'Obiettivo C non è consigliato e probabilmente non funzionerà. Vedi stackoverflow.com/a/38274660/2438634
Marc Etcheverry il

Sebbene l'override di UINavigationController funzioni sicuramente, sembra un bug sul lato Apple che non fa il childForStatusBarStyle per impostazione predefinita restituendo il suo topViewController. Ad esempio, UITabBarController lo fa per le sue schede. Per me, non c'è motivo per cui UINavigationController, essendo un controller strettamente contenitore per ospitare controller di visualizzazione "reali" piuttosto che presentare la propria interfaccia utente, dovrebbe "mangiare" quegli stili della barra di stato. Creerà un radar per Apple.
Igor Vasilev

1

Se nel caso in cui volessi nascondere la statusBar durante splashScreen ma volessi cambiare lo stile in un contenuto chiaro (StatusBarInitiallyHidden su Plist deve essere NO per nascondere statusBar su splash), puoi aggiungerlo al metodo didFinishLaunchingWithOptions di appDelegate per passare a lightContent.

[[UIApplication sharedApplication]setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
[[UIApplication sharedApplication]setStatusBarStyle:UIStatusBarStyleLightContent];

1

rapido esempio

in AppDelegate.swift

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
    UIApplication.sharedApplication().statusBarStyle = UIStatusBarStyle.LightContent;

    return true
}

in info.plist set Visualizza l'aspetto della barra di stato basata su controller: NO


1

Se stai usando NavigationController, puoi sottoclassareNavigationController modo che consulti il ​​suo controller di visualizzazione figlio

// MyCustomNavigationController

- (NSUInteger)supportedInterfaceOrientations {
    UIViewController *viewControllerToAsk = [self findChildVC];
    return [viewControllerToAsk supportedInterfaceOrientations];
}

- (BOOL)shouldAutorotate {
    UIViewController *viewControllerToAsk = [self findChildVC];
    return [viewControllerToAsk shouldAutorotate];
}

- (UIStatusBarStyle)preferredStatusBarStyle {
    UIViewController *viewControllerToAsk = [self findChildVC];
    return [viewControllerToAsk preferredStatusBarStyle];
}

- (UIViewController *)findChildVC {
    return self.viewControllers.firstObject;
}

1

Swift 4.2

extension UITabBarController {
    open override var childForStatusBarStyle: UIViewController? {
        return selectedViewController
    }
}

extension UINavigationController {
    open override var childForStatusBarStyle: UIViewController? {
        return visibleViewController
    }
}

Tieni presente che il metodo di estensione per eseguire l'override var non funziona più in Xcode 11.4 / iOS 13.4
Marc Etcheverry

@ MarcEtcheverry quindi, perché hai scartato la risposta? sembra strano.
Vyacheslav

Perché l'estensione delle classi C obiettivo in Swift viene implementata tramite le categorie C obiettivo. L'override dei metodi tramite le categorie dell'Obiettivo C non è consigliato e potrebbe non funzionare. Vedi stackoverflow.com/a/38274660/2438634
Marc Etcheverry il

@MarcEtcheverry "sconsigliato"! = "Non usarlo mai!". per jul2018 la risposta era corretta. Anche questa risposta non è aggiornata, questo non è un motivo per ridimensionarlo. Non riesco a vedere il futuro
Vyacheslav

0

È possibile impostare lo stile della barra di stato. Assomiglierà alla barra di stato come IOS 6 e sotto.
Incolla questi metodi nel controller della vista

-(UIStatusBarStyle)preferredStatusBarStyle{
    return UIStatusBarStyleBlackOpaque;
}

e chiamare questo metodo dalla vista è stato caricato in questo modo

if([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0f)
    {
       [self setNeedsStatusBarAppearanceUpdate];
    }

Intendi [self setStatusBarNeedsUpdate]nel secondo blocco? (O almeno qualcos'altro).
mxcl

0

Voglio solo aggiungere una nota per un caso specifico che ho affrontato. Avevo un'altra UIWindow nella mia app per visualizzare una faccia di chat che fluttuava in tutta la mia app tutto il tempo. In questo modo, nessuna delle soluzioni precedenti ha funzionato e non sono sicuro del perché! Tutto quello che ho notato è che il mio ViewController nella nuova UIWindow era la ragione di ciò! E se volessi cambiare lo stile della barra di stato devo farlo in quel view controller della nuova UIWindow.

Questa nota potrebbe aiutare gli altri che hanno una struttura simile! Quindi in pratica puoi applicare le soluzioni menzionate sopra nel ViewController della nuova UIWindow.

Anche questo è un caso specifico.

Grazie


-1

Per swift 3, nel tuo UIViewController:

override var preferredStatusBarStyle : UIStatusBarStyle { return UIStatusBarStyle.lightContent }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.