23 votes

SwiftUI - Hauteur de liste redimensionnable dépendant du nombre d'éléments

J'ai quelques problèmes avec le changement dynamique de la hauteur de la liste qui dépend du nombre d'éléments.

J'ai essayé cette solution mais elle n'a pas fonctionné.

List {
    ForEach(searchService.searchResult, id: \.self) { item in
        Text(item)
        .font(.custom("Avenir Next Regular", size: 12))
    }
}.frame(height: CGFloat(searchService.searchResult.count * 20))

29voto

John M. Points 5957

TL;DR

Ce n'est pas ainsi que les concepteurs de SwiftUI veulent que vous utilisiez les listes. Vous devrez soit trouver une solution de fortune qui sera probablement cassée à l'avenir (voir ci-dessous), soit utiliser autre chose qu'une liste.

Contexte

SwiftUI a tendance à avoir deux types de vues

  1. Ceux qui sont conçus pour être facilement modifiables et composables, offrant une personnalisation illimitée pour un aspect et une sensation uniques.
  2. Ceux qui sont conçus pour fournir une sensation standard et cohérente à un certain type d'interaction, quelle que soit l'application dans laquelle ils sont utilisés.

Un exemple de type 1 serait Texte. Vous pouvez modifier la taille et le poids de la police, le caractère, la couleur, l'arrière-plan, le remplissage, etc. Il est conçu pour que vous puissiez le modifier.

Un exemple de type 2 serait List. Vous ne contrôlez pas directement la hauteur des lignes, vous ne pouvez pas modifier le remplissage autour des vues, vous ne pouvez pas lui demander de n'afficher qu'un certain nombre de lignes, etc. Ils ne veulent pas qu'il soit très personnalisable, car les listes de chaque application se comporteraient alors différemment, ce qui irait à l'encontre de l'objectif d'un contrôle standard.

List est conçu pour remplir toute la vue parentale avec autant de lignes que possible, même si elles sont vides ou seulement partiellement à l'écran (et défiler s'il y en a trop pour les afficher en même temps).

Votre problème

Le problème que vous rencontrez vient du fait que la taille de la liste n'affecte en rien la taille de ses lignes. SwiftUI ne se soucie pas de savoir s'il y a trop ou trop peu de lignes pour que la liste tienne dans la taille que vous préférez ; il se contentera de dimensionner ses lignes en fonction du contenu, même si cela signifie qu'elles ne s'affichent pas toutes ou qu'il y a des lignes vides.

Si vous avez vraiment besoin que les rangées soient redimensionnées en fonction de la taille de leur parent, vous devriez utiliser un VStack. Si elles doivent défiler, vous devrez envelopper la VStack dans une ScrollView.

Solution de fortune

Si vous persistez à vouloir utiliser une liste, vous devrez procéder de la manière suivante :

struct ContentView: View {

    @State private var textHeight: Double = 20
    let listRowPadding: Double = 5 // This is a guess
    let listRowMinHeight: Double = 45 // This is a guess
    var listRowHeight: Double {
        max(listRowMinHeight, textHeight + 2 * listRowPadding)
    }

    var strings: [String] = ["One", "Two", "Three"]

    var body: some View {
        VStack {
            HStack {
                Text(String(format: "%2.0f", textHeight as Double))
                Slider(value: $textHeight, in: 20...60)
            }
                VStack(spacing: 0) {
                    Color.red
                    List {
                        ForEach(strings, id: \.self) { item in
                            Text(item)
                                .font(.custom("Avenir Next Regular", size: 12))
                                .frame(height: CGFloat(self.textHeight))
                                .background(Color(white: 0.5))
                        }
                    }
                    // Comment out the following line to see how List is expected to work
                    .frame(height: CGFloat(strings.count) * CGFloat(self.listRowHeight))
                    Color.red
            }.layoutPriority(1)
        }
    }
}

Le curseur est là pour montrer comment la hauteur des rangées de la liste change avec la hauteur de leur vue enfant. Vous devez choisir manuellement listRowPadding y listRowMinHeight pour obtenir l'apparence qui correspond le mieux à vos attentes. Si Apple modifie l'apparence d'une liste (modification du remplissage, de la hauteur minimale des lignes, etc.), vous devrez vous rappeler de revenir et d'ajuster ces valeurs manuellement.

24voto

Mojtaba Hosseini Points 2525

Taille propre List :

Si vous voulez un List pour afficher son contenu en une seule fois, ce qui signifie que vous n'avez pas besoin de la fonction de recyclage (la fonction clé de la liste). List ! Au lieu de cela, vous pouvez utiliser ForEach directement, puis il se dimensionnera en fonction de son contenu :

ForEach(searchService.searchResult, id: \.self) { item in
    VStack(alignment: .leading) {
        Text(item).font(.custom("Avenir Next Regular", size: 12))
        Divider()
    }.padding(.horizontal, 8)
}

Vous pouvez modifier toutes les tailles et tous les espacements en fonction de vos besoins.

Notez que Vous pouvez utiliser LazyVStack de iOS 14 pour le rendre paresseux et améliorer ses performances.

8voto

Michał Ziobro Points 1357

À partir d'iOS 14, vous pouvez utiliser LazyVStack au lieu de List . La liste semble couvrir toute la hauteur de la vue parent, indépendamment de la hauteur ou du nombre de lignes.

LazyVStack {
    ForEach(searchService.searchResult, id: \.self) { item in
        Text(item)
        .font(.custom("Avenir Next Regular", size: 12))
    }
}.frame(height: 

Une autre solution consiste à définir .frame(height: ) sur Liste basée sur rowCount*rowHeight ou autre GeometryReader -> geometry.size.height

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