web-dev-qa-db-fra.com

SWIFTUI - Hauteur de la liste redimensionnable qui dépend d'un nombre d'éléments

J'ai des problèmes avec une hauteur de liste de changement de manière dynamique qui dépend des éléments comptez.

J'ai essayé cette solution mais cela 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))
6
Abjox

TL; DR

Ce n'est pas la façon dont les concepteurs de swiftui veulent que vous utilisiez des listes. Soit vous devrez proposer une solution hacky qui va probablement casser à l'avenir (voir ci-dessous) ou utiliser autre chose qu'une liste.

arrière-plan

Swiftui a tendance à avoir deux types de vues

  1. Ceux qui sont conçus pour être facilement modifiables et composés, offrant une personnalisation illimitée pour un look unique et une sensation unique.
  2. Ceux qui sont conçus pour fournir une sensation standard et cohérente à un certain type d'interaction, quelle que soit leur application.

Un exemple de type 1 serait un texte. Vous pouvez modifier la taille de la police, le poids, la police de caractères, la couleur, l'arrière-plan, le rembourrage, etc. Il est conçu pour vous de la modifier.

Un exemple de type 2 serait la liste. Vous n'êtes pas en contrôle direct de la hauteur de la rangée, vous ne pouvez pas changer le rembourrage des vues, vous ne pouvez pas le dire de montrer que de nombreuses lignes, etc. Ils ne veulent pas que ce soit très personnalisable, car alors chaque application Les listes se comporteraient différemment, vaincre le but d'un contrôle standard.

La liste est conçue pour remplir l'ensemble de la vue parent avec autant de lignes que possible, même s'ils sont vides ou partiellement à l'écran (et faites défiler en cas de trop nombreux pour montrer à la fois).

Votre problème

Le problème que vous rencontrez concerne car la taille de la liste n'affecte aucune manière la taille de ses rangées. Swiftui ne se soucie pas s'il y a trop de rangées ou trop peu de lignes pour s'adapter à votre taille préférée; Il sera heureux de former ses lignes en fonction du contenu, même si cela signifie qu'ils ne montrent pas tous ou qu'il y a des rangées vides montrées.

Si vous avez vraiment besoin de lignes pour redimensionner en fonction de la taille de leur parent, vous devez utiliser un vstack. Si cela doit faire défiler, vous devrez envelopper le VStack dans une enveloppe de défilement.

solution hacky

Si vous insistez toujours sur l'utilisation d'une liste, vous devrez faire quelque chose comme ce qui suit:

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 les hauteurs de la ligne de liste changent avec la hauteur de la vue de leur enfant. Vous devriez choisir manuellement listRowPadding et listRowMinHeight pour obtenir l'apparence qui correspond le mieux à vos attentes. Si Apple modifie déjà la manière dont une liste a l'air (modification du rembourrage, des hauteurs minimales de ligne, etc.) Vous devrez vous rappeler de revenir manuellement et d'ajuster ces valeurs manuellement.

7
John M.

Taille de soi List:

Si vous voulez un List pour afficher son contenu tout à la fois, cela signifie que vous n'avez pas besoin de la fonctionnalité de recyclage (la fonction clé de la liste), de sorte que tout ce dont vous avez besoin est de ne pas utiliser de List! Au lieu de cela, vous pouvez utiliser ForEach directement, puis il se formera 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 changer toutes les tailles et les espacements en fonction de vos besoins

1
Mojtaba Hosseini