9
votes

Comment styliser les lignes dans la liste SwiftUI sur WatchOS?

Je travaille avec SwiftUI et j'essaie de créer une liste de boutons avec .buttonStyle personnalisé dans une vue Liste sur WatchOS, mais je ne parviens pas à le faire fonctionner. Est-ce même actuellement possible, et si oui, comment?

Exemple de projet:

struct Superhero: Identifiable {
    var id = UUID()
    var name: String
}

var superheroes = [
    Superhero(name: "Batman"),
    Superhero(name: "Superman"),
    Superhero(name: "Wonder Woman"),
    Superhero(name: "Aquaman"),
    Superhero(name: "Green Lantern"),
    Superhero(name: "The Flash")
]

struct SuperheroButtonStyle: ButtonStyle {

  func makeBody(configuration: Self.Configuration) -> some View {
    configuration.label
        .frame(minWidth: 0, maxWidth: .infinity)
        .foregroundColor(.white)
        .background(configuration.isPressed ? Color.white.opacity(0.95) : .green)
        .cornerRadius(13.0)
  }
}

struct SuperHeroesView: View{
    var body: some View {
        List {

            ForEach(superheroes) { superhero in
                Button(action: {
                    print(superhero.name)
                }){
                    Text(superhero.name)
                }.buttonStyle(SuperheroButtonStyle())
           }

       }
    }
}

Ce code produit ceci:image de l'application WatchOS

Au lieu de cela, je veux que les boutons ressemblent davantage à ceci:

image du résultat recherché

Dans ce dernier exemple, j'utilise ScrollView au lieu de List, ce qui signifie que je n'obtiens pas la belle animation des lignes qui rétrécissent et disparaissent lors du défilement de la liste.

J'ai essayé de jouer avec un rembourrage négatif, mais cela ne peut pas me donner un plus grand rayon de coin (plus de coins arrondis que la valeur par défaut) et ne semble pas vraiment bon.

Existe-t-il donc un moyen d'appliquer correctement un ButtonStyle aux éléments d'une vue Liste, y compris en ayant un cornerRadius personnalisé?

Ou existe-t-il un autre moyen d'obtenir plus de contrôle sur l'apparence des lignes tout en conservant l'animation fournie avec List?


3 commentaires

J'aimerais aussi savoir s'il existe un moyen de le faire correctement!


J'ai essayé de faire ça aussi. Il y a une propriété que vous pouvez ajouter sur une liste appelée listStyle je n'ai pas réussi à faire fonctionner. De plus, j'ai essayé de mettre en œuvre ce que vous avez fait (deux vues avec le marqueur de point en bas) Pouvez-vous peut-être aider?


Plutôt que de publier une réponse qui pourrait manquer le point, avez-vous envisagé d'appliquer .listStyle(CarouselListStyle()) à votre List ?


6 Réponses :


-1
votes
struct SuperHeroesView: View{
        var body: some View {
            List {
                ForEach(superheroes) { superhero in
                    Button(action: {
                        print(superhero.name)
                    }){
                        Text(superhero.name)
                    }.buttonStyle(SuperheroButtonStyle())
                        .listRowInsets(EdgeInsets())
                        .listRowBackground(Color.clear)
                }.environment(\.defaultMinListRowHeight, 20)

            }
        }
    }

0 commentaires

0
votes

Je sais que ce n'est pas ainsi que cela est censé être implémenté, mais il semble qu'il y ait un bogue dans SwiftUI empêchant listRowPlatterColor , listRowBackground ou même listRowInsets de faire quoi que ce soit dans la dernière version de watchOS.

Voici comment je l'ai contourné pour l'instant:

ZStack {
    Color.black
    MyRowView()
}
    .padding(.horizontal, -8)


0 commentaires

1
votes

Pour avoir l'arrière-plan de la cellule entière dans une certaine couleur, vous devez utiliser le modificateur .listRowBackground . Vous pouvez utiliser une Capsule ou un RoundedRectangle comme arrière-plan selon vos préférences:

struct SuperheroButtonStyle: ButtonStyle {

  func makeBody(configuration: Self.Configuration) -> some View {
    configuration.label
        .frame(minWidth: 0, maxWidth: .infinity)
        .foregroundColor(configuration.isPressed ? .gray : .white)
  }
}

Vous voudrez probablement également changer le style du bouton, car l'effet de surbrillance d'arrière-plan n'affectera que le bouton, pas la cellule entière:

struct SuperHeroesView: View{
    var body: some View {
        List {
            ForEach(superheroes) { superhero in
                Button(action: { print(superhero.name) }){
                    Text(superhero.name)
                }   .buttonStyle(SuperheroButtonStyle())
            }   .listRowBackground(Capsule()
                                       .fill(Color.green))
                // or as an alternative:
                //.listRowBackground(RoundedRectangle(cornerRadius: 13.0)
                //                       .fill(Color.green))
       }
    }
}


0 commentaires

5
votes

Je ne sais pas si vous l'avez encore compris ou non, mais j'ai fini par utiliser

.listRowPlatterColor(.clear)

pour étendre les bords de mes boutons jusqu'au bord de la liste comme ceci:

Lignes avec des bords étendus

Vous pouvez également ajouter le modificateur

.environment(\.defaultMinListRowHeight, 20)

à la liste elle-même pour permettre à la hauteur des lignes de se réduire à la taille souhaitée. J'ai choisi 20 pour cet exemple:

Hauteur de ligne correctement dimensionnée

Et enfin il y a un

List {

        ForEach(superheroes) { superhero in
            Button(action: {
                print(superhero.name)
            }){
                Text(superhero.name)
            }
            .buttonStyle(SuperheroButtonStyle())
            .listRowInsets(EdgeInsets.init(top: 0, leading: 0, bottom: 0, trailing: 0))
       }

   }

modificateur que vous pouvez utiliser pour changer la couleur d'arrière-plan de la ligne elle-même. J'ai choisi clear pour cet exemple pour masquer les bords qui ne sont pas entièrement couverts par le bouton.

Plateau transparent


1 commentaires

J'ai toujours ce petit peu de gris du style par défaut du bouton laissé sur WatchOS. Me rend fou! Mais merci pour cela, cela a aidé.



5
votes

.listRowPlatterColor (.clear) M'a donné ce que je cherchais. C'était probablement plus difficile que nécessaire de le trouver.

struct ContentView: View {
    @State private var EnrouteText = "Enroute"
    var body: some View {
        List {
            Button(action: {
                self.EnrouteText = getCurrentTime()
            }) {
                Text(EnrouteText)
            }
            .buttonStyle(BtnStyle(bgColor: .red, fgColor: .white))
            .listRowInsets(EdgeInsets.init(top: 0, leading: 0, bottom: 0, trailing: 0))
            .listRowPlatterColor(.clear)

            // The rest of the buttons.
        }
    }
}

// Button Styles
struct BtnStyle: ButtonStyle {
    var bgColor: Color
    var fgColor: Color

    func makeBody(configuration: Self.Configuration) -> some View {
        configuration.label
            .frame(minWidth: 0, maxWidth: .infinity)
            .padding()
            .foregroundColor(fgColor)
            .background(bgColor)
            .cornerRadius(32)
    }
}

Exemple d'utilisation de listRowPlatterColor pour effacer la dernière partie de l'arrière-plan


0 commentaires

1
votes

Selon les directives de l'interface humaine , il est recommandé que les boutons d'une vue défilante (par exemple, List ) ressemblent à un rectangle arrondi (plutôt qu'à une capsule).

Si vous essayez d'utiliser .listRowBackground , vous obtiendrez un rectangle net (non souhaité):

entrez la description de l'image ici

Si vous utilisez à la place .listRowPlatterColor , vous obtiendrez exactement ce qu'Apple vous recommande d'utiliser (dans une ligne de code, néanmoins):

entrez la description de l'image ici

Button("Log out") {}
  .listRowPlatterColor(Color.blue)


0 commentaires