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))
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
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.
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