Existe-t-il un moyen de changer la barre d'état en blanc pour une vue SwiftUI?
Il me manque probablement quelque chose de simple, mais je n'arrive pas à trouver un moyen de changer la barre d'état en blanc dans SwiftUI. Jusqu'à présent, je vois juste .statusBar(hidden: Bool)
.
13 Réponses :
Comme dans les commentaires liés à j'ai édité cette question ici
Mais pour répondre à cette question et aider les gens à trouver la réponse directement:
Swift 5 et SwiftUI
Pour SwiftUI, créez un nouveau fichier swift appelé HostingController.swift
window.rootViewController = HostingController(rootView: ContentView())
Modifiez ensuite les lignes de code suivantes dans SceneDelegate.swift
window.rootViewController = UIHostingController(rootView: ContentView())
à
import SwiftUI class HostingController<ContentView>: UIHostingController<ContentView> where ContentView : View { override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent } }
Quoi qu'il en soit pour changer la couleur de la barre d'état de SwiftUI? Ie si vous montrez un modal qui a besoin d'une barre d'état différente?
Avec cela, j'imagine que vous devez garder à l'esprit que le mode sombre peut avoir besoin d'affecter cette valeur
Cela ne fonctionne pas si vous avez des objets d'environnement.
Pas besoin d'importer Foundation ou UIKit, et plus généralement UIKit inclut Foundation donc pas besoin d'importer Foundation lors de l'importation d'UIKit
C'est vrai, j'ai édité la réponse. J'avais un autre code dans le fichier qui nécessitait UIKit ... Foundation est toujours importé lors de l'ajout d'un fichier swift dans Xcode ... @alexisSchreier
@ keegan3d ne l'a pas essayé donc je ne sais pas actuellement
@RichardWitherspoon J'ai publié une nouvelle réponse avec des solutions fonctionnelles pour les objets d'environnement
Qu'en est-il du nouveau cycle de vie SwiftUI?
Créez un contrôleur d'hébergement, DarkHostingController
et définissez-y le preferredStatusBarStyle
:
window.rootViewController = DarkHostingController(rootView: ContentView())
et enveloppez dans SceneDelegate
:
class DarkHostingController<ContentView> : UIHostingController<ContentView> where ContentView : View { override dynamic open var preferredStatusBarStyle: UIStatusBarStyle { .lightContent } }
Cela fonctionne pour changer la couleur du texte du noir au blanc, mais comment puis-je changer la couleur d'arrière-plan de la barre d'état?
@MobileMon, vous utilisez .edgesIgnoringSafeArea (.top) pour permettre à votre arrière-plan de remonter jusqu'en haut et vous pouvez définir cette couleur. Vous mettez cela directement sur la vue.
Qu'est-ce que "Model ()"? Vous ne l'avez pas défini.
@RichardWitherspoon Model est mon objet de modèle de données et vous n'en avez pas besoin pour cette solution. Je vais le supprimer, pour éviter toute confusion.
J'aime l'utilisation de génériques pour dissocier le contrôleur d'un type spécifique (contrairement à la réponse la plus votée), cependant, quel serait l'intérêt d'utiliser '@objc' et 'dynamic open' dans ce cas d'utilisation spécifique?
Créez une nouvelle classe appelée HostingController
:
import SwiftUI final class HostingController<T: View>: UIHostingController<T> { override var preferredStatusBarStyle: UIStatusBarStyle { .lightContent } }
Dans votre SceneDelegate.swift
, remplacez toutes les occurrences de UIHostingController
par HostingController
.
Dans le cas où vous utilisez environmentObject
vous pouvez utiliser la solution proposée dans cette réponse .
Créez un nouveau fichier et collez le code suivant
window.rootViewController = HostingController(rootView: AnyView(contentView.environmentObject(settings)))
La différence ici est que nous utilisons AnyView
au lieu de ContentView
, ce qui nous permet de remplacer ceci:
window.rootViewController = UIHostingController(rootView:contentView.environmentObject(settings))
par ça:
import SwiftUI class HostingController: UIHostingController<AnyView> { override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent } }
Comment la performance? J'ai vu des mentions que l'utilisation d'AnyView a un impact négatif sur les performances.
Mon application n'est pas lourde, donc je n'ai remarqué aucune différence, mais je ne peux pas confirmer pour les applications plus lourdes
J'utilise quelque chose comme ça
extension UIApplication { enum ColorMode { case dark, light } class func setStatusBarTextColor(_ mode: ColorMode) { if #available(iOS 13.0, *) { var style: UIUserInterfaceStyle switch mode { case .dark: style = .dark default: style = .light } if let window = Self.activeSceneDelegate?.window as? UIWindow { window.overrideUserInterfaceStyle = style window.setNeedsDisplay() } } } class var activeSceneDelegate: UIWindowSceneDelegate? { (Self.activeScene)?.delegate as? UIWindowSceneDelegate } }
Erreur: le type «Self» n'a pas de membre «activeScene». Veuillez également partager votre extension UIApplication avec nous. Merci.
Mise à jour : Il semble que la réponse de Hannes Sverrisson ci-dessus soit la plus proche, mais nos réponses sont légèrement différentes.
Les réponses ci-dessus avec la sous-classe UIHostingController, telles qu'écrites, ne fonctionnent pas dans XCode 11.3.1.
Ce qui suit a fonctionné pour moi, pour la sous-classe (qui gère également les paramètres d'environnement ContentView):
window.rootViewController = HostingController(rootView: contentView)
Ensuite, dans SceneDelegate.swift, modifier le paramètre window.rootViewController
en tant que tel fonctionne effectivement:
import SwiftUI class HostingController<Content>: UIHostingController<Content> where Content : View { override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent } }
Je pense que c'est une bonne solution et cela fonctionne pour moi.
La solution ci-dessus fonctionne pour le style de la barre d'état. Si vous souhaitez appliquer une couleur d'arrière-plan à la barre d'état, vous devez utiliser un VStack qui ignore la zone d'enregistrement supérieure.
GeometryReader{geometry in VStack{ Rectangle().frame(width: geometry.size.width, height: 20, alignment: .center).foregroundColor(.red) Spacer() Your content view goes here } .frame(width: geometry.size.width, height: geometry.size.height) }.edgesIgnoringSafeArea(.top)
Vous pouvez utiliser la hauteur réelle de la barre d'état au lieu de 20 fixe. Veuillez vous référer au lien ci-dessous pour obtenir la hauteur de la barre d'état. Hauteur de la barre d'état dans Swift
Dans info.plist, vous pouvez simplement définir
Pas besoin de changer quoi que ce soit dans votre code ...
Ne semble rien faire avec une application SwiftUI.
Le texte barre d'état / teinte / couleur de premier plan peut être réglé sur blanc en réglant la View
de .dark
ou .light
schéma de couleurs de mode à l' aide .preferredColorScheme(_ colorScheme: ColorScheme?)
.
La première vue de votre hiérarchie qui utilise cette méthode prévaudra.
Par exemple:
var body: some View { ZStack { ... } .preferredColorScheme(.light) // black tint on status bar }
var body: some View { ZStack { ... } .preferredColorScheme(.dark) // white tint on status bar }
Merci. C'est la manière actuelle de SwiftUI.
Je pense que cela changera complètement le jeu de couleurs, pas seulement la couleur du texte de la barre d'état. Si votre application utilise un thème sombre, ce n'est pas une solution viable
Bonne réponse, mais cela peut entraîner plus de tracas car cela changera également les schémas de couleurs des listes et d'autres objets à l'intérieur de cette pile. Changer uniquement le UIStatusBar évitera cela et sera moins code techniquement.
Créez un nouveau fichier swift appelé HostingController.swift ou ajoutez simplement cette classe à votre fichier swift existant
window.rootViewController = HostingController(rootView: contentView)
Puis changez la ligne de code dans SceneDelegate.swift
window.rootViewController = UIHostingController(rootView: contentView)
à
class HostingController: UIHostingController<ContentView> { override var preferredStatusBarStyle: UIStatusBarStyle { return .darkContent //or .lightContent } }
Les réponses existantes couvrent le cas où vous souhaitez simplement changer la couleur de la barre d'état une fois (par exemple, utilisez du contenu léger dans toute votre application), mais si vous souhaitez le faire par programme, les clés de préférence sont un moyen d'y parvenir.
L'exemple complet peut être trouvé ci-dessous, mais voici une description de ce que nous allons faire:
PreferenceKey
, elle sera utilisée par View
s pour définir leur style de barre d'état préféréUIHostingController
qui peut détecter les changements de préférence et les relier au code UIKit appropriéView
extension pour obtenir une API qui semble presque officielleVStack { Text("Something") }.statusBar(style: .lightContent)
//Previously: window.rootViewController = UIHostingController(rootView: rootView) window.rootViewController = HostingController(wrappedView: rootView)
extension View { func statusBar(style: UIStatusBarStyle) -> some View { preference(key: StatusBarStyleKey.self, value: style) } }
Tout d'abord, dans votre SceneDelegate
vous devrez remplacer UIHostingController
par votre sous-classe:
class HostingController: UIHostingController<AnyView> { var statusBarStyle = UIStatusBarStyle.default //UIKit seems to observe changes on this, perhaps with KVO? //In any case, I found changing `statusBarStyle` was sufficient //and no other method calls were needed to force the status bar to update override var preferredStatusBarStyle: UIStatusBarStyle { statusBarStyle } init<T: View>(wrappedView: T) { // This observer is necessary to break a dependency cycle - without it // onPreferenceChange would need to use self but self can't be used until // super.init is called, which can't be done until after onPreferenceChange is set up etc. let observer = Observer() let observedView = AnyView(wrappedView.onPreferenceChange(StatusBarStyleKey.self) { style in observer.value?.statusBarStyle = style }) super.init(rootView: observedView) observer.value = self } private class Observer { weak var value: HostingController? init() {} } @available(*, unavailable) required init?(coder aDecoder: NSCoder) { // We aren't using storyboards, so this is unnecessary fatalError("Unavailable") } }
Toutes les vues peuvent désormais utiliser votre extension pour spécifier leur préférence:
struct StatusBarStyleKey: PreferenceKey { static var defaultValue: UIStatusBarStyle = .default static func reduce(value: inout UIStatusBarStyle, nextValue: () -> UIStatusBarStyle) { value = nextValue() } }
La solution d'utiliser une sous-classe HostingController pour observer les changements de clé de préférence a été suggérée dans cette réponse à une autre question - j'avais précédemment utilisé @EnvironmentObject qui avait beaucoup d'inconvénients, les clés de préférence semblent beaucoup plus adaptées à ce problème.
Est-ce la bonne solution à ce problème? Je ne suis pas sûr. Il y a probablement des cas extrêmes que cela ne gère pas, par exemple, je n'ai pas testé en profondeur pour voir quelle vue obtient la priorité si plusieurs vues dans la hiérarchie spécifient une clé de préférence. Dans mon propre usage, j'ai deux vues mutuellement exclusives qui spécifient leur style de barre d'état préféré, donc je n'ai pas eu à gérer cela. Vous devrez peut-être modifier cela pour répondre à vos besoins (par exemple, utiliser un tuple pour spécifier à la fois un style et une priorité, puis demander à votre HostingController
vérifier sa priorité précédente avant de remplacer).
La réponse de @Dan Sandland a fonctionné pour moi, mais dans mon cas, il était nécessaire de garder l'interface en mode .light
ZStack { Rectangle()... VStack(spacing: 0) { ... }.colorScheme(.light) } .preferredColorScheme(.dark)
Ajoutez simplement ceci à info.plist
<key>UIStatusBarStyle</key> <string>UIStatusBarStyleLightContent</string> <key>UIViewControllerBasedStatusBarAppearance</key> <false/>
testé sur IOS 14, xcode 12
Voulez-vous dire l'arrière-plan de la barre d'état ou le texte de la barre d'état?
Texte de la barre d'état, passage au style d'éclairage
Essayez-vous de le modifier pour l'ensemble de l'application ou pour une seule vue?
L'application entière serait bien, mais ce serait bien de savoir comment changer une seule vue
Pour les changements globaux, je peux utiliser
UIApplication.shared.statusBarStyle = .lightContent
mais j'obtiens un avertissement dans Xcode que cela était obsolète dans iOS 13. Mais quand j'essaye de définir ceci sur la scène de la fenêtre:windowScene.statusBarManager?.statusBarStyle = .light
Cannot assign to property: 'statusBarStyle' is a get-only property
une erreur qui:Cannot assign to property: 'statusBarStyle' is a get-only property
Voir cette question: stackoverflow.com/questions/17678881/...
Parfait, le code pour sous-
UIHostingController
était ce dont j'avais besoin, merci!Copie possible de Comment changer la couleur du texte de la barre d'état dans iOS