89 votes

SwiftUI met à jour la couleur du titre de la barre de navigation

Comment changer la couleur du titre de la barre de navigation dans SwiftUI

NavigationView {
            List{
                ForEach(0..<15) { item in
                    HStack {
                        Text("Apple")
                            .font(.headline)
                            .fontWeight(.medium)
                            .color(.orange)
                            .lineLimit(1)
                            .multilineTextAlignment(.center)
                            .padding(.leading)
                            .frame(width: 125, height: nil)

                        Text("Apple Infinite Loop. Address: One Infinite Loop Cupertino, CA 95014 (408) 606-5775 ")
                            .font(.subheadline)
                            .fontWeight(.regular)
                            .multilineTextAlignment(.leading)
                            .lineLimit(nil)

                    }
                }
            }
            .navigationBarTitle(Text("TEST")).navigationBarHidden(false).foregroundColor(.orange)
            }

J'ai essayé avec .foregroundColor(.orange) mais cela ne fonctionne pas

a également essayé .navigationBarTitle(Text("TEST").color(.orange))

Comment faire ?

3 votes

Hm... il semble que swiftUI ignore tout modificateur défini pour le titre de la barre de navigation... Et il est également étrange que nous ne pouvons pas mettre n'importe quelle vue dans la barre de navigation :-(

2voto

Kirill Points 609

Il y a certainement déjà quelques bonnes réponses, mais elles ne couvrent toutes qu'une partie du travail :

  1. Excellente solution de la part de @arsenius - donner le bon point de départ

  2. Une manière élégante de @EngageTheWarpDrive - cela améliore définitivement la convivialité

  3. Pour la dernière version d'iOS et swiftUI @Thahir suggérer l'utilisation de la barre d'outils

Quelques suggestions supplémentaires proposent d'utiliser UIAppearence configuration globale pour UINavigationBar - Pour ma part, le changement global n'est pas une bonne idée et n'est peut-être pas toujours approprié.

J'ai fini par combiner toutes les propositions dans le code suivant :

  1. Créer NavigationControllerRepresentable y modifier para navigationBar configuration :

     struct NavigationControllerLayout: UIViewControllerRepresentable {
    
         var configure: (UINavigationController) -> () = { _ in }
    
         func makeUIViewController(
             context: UIViewControllerRepresentableContext<NavigationControllerLayout>
         ) -> UIViewController {
             UIViewController()
         }
    
         func updateUIViewController(
             _ uiViewController: UIViewController,
             context: UIViewControllerRepresentableContext<NavigationControllerLayout>
         ) {
             if let navigationContoller = uiViewController.navigationController {
                 configure(navigationContoller)
             }
         }
     }
    
     extension View {
    
         func configureNavigationBar(_ configure: @escaping (UINavigationBar) -> ()) -> some View {
             modifier(NavigationConfigurationViewModifier(configure: configure))
         }
     }
    
     struct NavigationConfigurationViewModifier: ViewModifier {
    
         let configure: (UINavigationBar) -> ()
    
         func body(content: Content) -> some View {
             content.background(NavigationControllerLayout(configure: {
                 configure($0.navigationBar)
             }))
         }
     }
  2. Pour modifier navigationBar pour répondre à vos exigences (telles que la couleur du fond et d'autres accessoires) :

    extension UINavigationBar {
    
         enum Appearence {
    
             case transparent
             case defaultLight
             case colored(UIColor?)
    
             var color: UIColor {
                 ...
             }
    
             var appearenceColor: UIColor {
                 ...
             }
    
             var tint: UIColor {
                 ....
             }
    
             var effect: UIBlurEffect? {
                ....
             }
         }
    
         func switchToAppearence(_ type: Appearence) {
             backgroundColor = type.color
             barTintColor = type.tint
    
             // for iOS 13+
             standardAppearance.backgroundColor = type.appearenceColor
             standardAppearance.backgroundEffect = type.effect
    
             // u can use other properties from navBar also simply modifying this function
         }
     }
  3. Comme vous pouvez le voir, ici nous avons besoin d'un pont entre Color y UIColor . A partir de iOS 14 - tu peux juste UIColor.init(_ color: Color) mais avant iOS 14 il n'y a pas de tel moyen, donc j'ai fini par trouver une solution simple :

     extension Color {
    
         /// Returns a `UIColor` that represents this color if one can be constructed
         ///
         /// Note: Does not support dynamic colors
         var uiColor: UIColor? {
             self.cgColor.map({ UIColor(cgColor: $0) })
         }
     }

cela ne fonctionnera pas pour les couleurs dynamiques

  1. Vous pouvez donc l'utiliser comme suit :

     // modifier to `NavigationView`
     .configureNavigationBar {
         $0.switchToAppearence(.defaultLight)
     }

J'espère que cela pourra aider quelqu'un ;)

2voto

cliss Points 56

J'ai adopté une approche légèrement différente ; je voulais changer sólo la couleur du texte du titre, et rien d'autre sur la NavigationBar . En utilisant ce qui précède et ce comme inspiration, j'ai atterri sur :

/// Sets the text color for a navigation bar title.
/// - Parameter color: Color the title should be
///
/// Supports both regular and large titles.
@available(iOS 14, *)
func navigationBarTitleTextColor(_ color: Color) -> some View {
    let uiColor = UIColor(color)

    // Set appearance for both normal and large sizes.
    UINavigationBar.appearance().titleTextAttributes = [.foregroundColor: uiColor ]
    UINavigationBar.appearance().largeTitleTextAttributes = [.foregroundColor: uiColor ]

    return self
}

Cela nécessite iOS 14 car UIColor.init(_ color: Color) nécessite iOS 14.

Qui peut être exploité comme tel :

struct ExampleView: View {
    var body: some View {
        NavigationView {
            Text("Hello, World!")
                .navigationBarTitle("Example")
                .navigationBarTitleTextColor(Color.red)
        }
    }
}

Ce qui, à son tour, donne :

Red navigation title

1voto

kdion4891 Points 336

Je n'ai toujours pas trouvé comment faire la couleur de l'avant-plan sur une base par vue, mais j'ai trouvé une solution simple pour la couleur de l'arrière-plan.

Si vous utilisez un .inline vous pouvez simplement utiliser un VStack avec un rectangle en haut de la NavigationView :

NavigationView {
    VStack() {
        Rectangle()
            .foregroundColor(.red)
            .edgesIgnoringSafeArea(.top)
            .frame(height: 0)

        List {
            Text("Hello World")
            Text("Hello World")
            Text("Hello World")
        }
    }
    .navigationBarTitle("Hello World", displayMode: .inline)
    // ...

Notez comment le rectangle utilise une hauteur de cadre de 0 y .edgesIgnoringSafeArea(.top) .

1voto

Austin Conlon Points 88

J'ai rencontré cette limitation dans mon application indépendante Apple Watch. Bien que cette correction ne soit pas strictement dans SwiftUI, je suis allé dans le fichier Interface.storyboard, j'ai sélectionné le contrôleur d'hébergement, j'ai sélectionné l'inspecteur de fichiers sur la droite, puis j'ai défini la couleur à côté de Global Tint sous la section Document Interface Builder.

1voto

rnr-a-np Points 21

Mise à jour pour 13.4

note : en réexaminant cette question le lendemain, il est possible que certains de mes problèmes aient été causés par ma configuration quelque peu atypique : je suis toujours sous mojave, mais j'ai ajouté manuellement les fichiers de support 13.4 (normalement disponibles uniquement via xcode 11.4, qui nécessite catalina). je mentionne ceci parce que j'ai/avais également des problèmes de couleur personnalisée de la barre d'onglets, mais je viens de remarquer que ceux-ci ne se manifestent que lorsque j'ai le téléphone branché et que j'exécute l'application depuis xcode. si je débranche et que j'exécute l'application normalement, je ne vois pas les problèmes de la barre d'onglets, il est donc possible que le problème de la barre de navigation ait une certaine similitude ...

(j'ajouterais bien ceci en commentaire de la réponse d'arsenius (celle qui est actuellement acceptée) ci-dessus, mais je n'ai pas de représentant, donc ...)

J'utilisais cette solution et elle fonctionnait parfaitement jusqu'à la version 13.4, qui semble l'avoir cassée, du moins pour moi. Après de nombreuses recherches sur la hiérarchie des vues, il semble qu'ils aient modifié les choses de telle sorte que le UINavigationController implicite n'est plus facilement accessible via le UIViewController passé, comme décrit dans la solution de contournement. Il est toujours là cependant (assez loin dans l'arbre), il faut juste le trouver.

à cette fin, nous pouvons simplement parcourir la hiérarchie des vues jusqu'à ce que nous trouvions la barre de navigation, et ensuite définir les paramètres souhaités sur celle-ci, comme d'habitude. cela nécessite une nouvelle fonction de découverte, et quelques changements mineurs à la structure NavigationConfigurator, et son instanciation ...

Tout d'abord, la fonction de découverte :

func find_navbar(_ root: UIView?) -> UINavigationBar?
{
    guard root != nil else { return nil }

    var navbar: UINavigationBar? = nil
    for v in root!.subviews
    {   if type(of: v) == UINavigationBar.self { navbar = (v as! UINavigationBar); break }
        else { navbar = find_navbar(v); if navbar != nil { break } }
    }

    return navbar
}

modifier le NavigationConfigurator comme suit (notez que nous ne nous soucions plus de passer dans une vue, puisque ce n'est plus fiable) :

struct NavigationConfigurator: UIViewControllerRepresentable
{
    @EnvironmentObject var prefs: Prefs     // to pick up colorscheme changes

    var configure: () -> Void = {}
    func makeUIViewController(context: UIViewControllerRepresentableContext<NavigationConfigurator>) -> UIViewController { UIViewController() }
    func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<NavigationConfigurator>) { self.configure() }
}

(dans mon application, j'ai un objet Prefs qui garde la trace des couleurs, etc.)

... puis, au site d'instanciation, faites quelque chose comme ceci :

MyView()
    .navigationBarTitle("List", displayMode: .inline)
    .navigationBarItems(trailing: navbuttons)
    .background(NavigationConfigurator {
        if self.prefs.UI_COLORSCHEME != Colorscheme.system.rawValue
        {   if let navbar = find_navbar(root_vc?.view)
            {   navbar.barTintColor = Colors.uicolor(.navbar, .background)
                navbar.backgroundColor = .black
                navbar.titleTextAttributes = [.foregroundColor: Colors.uicolor(.navbar, .foreground)]
                navbar.tintColor = Colors.uicolor(.navbar, .foreground)
            }
        }
    })

notez que j'ai capturé le contrôleur de vue Root ailleurs dans mon application, et que je l'utilise ici pour le passer à find_navbar(). vous pourriez vouloir le faire différemment, mais j'ai déjà cette variable pour d'autres raisons ... il y a d'autres choses spécifiques à mon application, par exemple, les objets liés à la couleur, mais vous voyez l'idée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X