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
- Ceux qui sont conçus pour être facilement modifiables et composables, offrant une personnalisation illimitée pour un aspect et une sensation uniques.
- 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.