List est une View conteneur dans SwiftUI pour afficher des données sous forme de liste verticalement défilable, analogue à UITableView dans UIKit. Selon Apple Developer Documentation, 2024, List prend en charge les sections statiques et dynamiques, les actions de balayage, le réordonnancement des lignes et le pull-to-refresh. Contrairement à UITableView, List utilise une API déclarative basée sur SwiftUI et ForEach, gérant automatiquement la réutilisation des cellules et les performances avec un grand nombre de lignes.
Points clés
List est une View qui affiche une séquence d'éléments dans une liste verticalement défilable. Elle a été introduite dans iOS 13 avec SwiftUI et est la principale façon d'afficher des listes de données, remplaçant UITableView d'UIKit. List gère automatiquement la réutilisation des cellules, le défilement et les performances.
List utilise le lazy-loading : les cellules sont créées au fur et à mesure du défilement, pas toutes à la fois. Cela le distingue de VStack avec ForEach dans ScrollView, où toutes les cellules sont créées au moment du rendu. List fournit également une prise en charge intégrée pour les actions de balayage, le pull-to-refresh, l'édition (supprimer/déplacer) et la sélection de lignes.
Selon Apple WWDC 2021 (Session 10072), List dans iOS 15+ a reçu des améliorations significatives des performances grâce à un nouveau mécanisme de diffing au niveau des collections. Cela a rendu List plus efficace lors de la mise à jour des données, en particulier pour les listes contenant des centaines de lignes.
Les développeurs choisissent souvent entre List et ScrollView avec VStack pour afficher un ensemble de Views. La différence clé : List utilise la réutilisation des cellules (comme UITableView), tandis que ScrollView + VStack crée toutes les Views immédiatement. Pour les listes de taille fixe (jusqu'à 20 éléments), la différence est négligeable. Pour les listes dynamiques de 50+ lignes, List est préférable pour les performances.
Liste statique est une liste avec un nombre fixe de lignes spécifiées directement dans le corps de List. Elle est utilisée pour les menus, les paramètres et les formulaires avec un ensemble connu d'éléments. Chaque ligne est déclarée explicitement, sans boucles ni ForEach.
// Liste statique (pour menus et paramètres)
List {
Text("Profil")
Text("Paramètres")
Text("À propos")
}
// Liste dynamique (pour données)
struct UserList: View {
let users: [User]
var body: some View {
List(users) { user in
HStack {
Text(user.name)
Text(user.role)
.foregroundColor(.secondary)
}
}
}
}
Liste dynamique utilise l'initialiseur List(data:rowContent:) ou ForEach à l'intérieur du corps de List. La première approche est pratique lorsque chaque ligne correspond à un élément de données. La seconde est utile lorsqu'il y a des sections ou des éléments supplémentaires entre les données.
Identification (Identifiable) : Pour les listes dynamiques, les éléments de données doivent se conformer au protocole Identifiable, ou vous devez spécifier un KeyPath vers un identifiant unique dans le tuple data:id. SwiftUI utilise les identifiants pour suivre les changements : ajouts, suppressions et déplacements de lignes.
Section est une View pour regrouper les lignes dans une List avec un en-tête et un footer optionnel. Section accepte header et footer comme ViewBuilder, permettant d'utiliser non seulement du texte mais aussi des Views personnalisées pour les en-têtes de section.
struct SettingsView: View {
var body: some View {
List {
Section(header: Text("Compte")) {
Text("Nom")
Text("Email")
}
Section(header: Text("Notifications")) {
Toggle("Push", isOn: $pushEnabled)
Toggle("Email", isOn: $emailEnabled)
}
}
.listStyle(.insetGrouped)
}
}
// Sections dynamiques avec ForEach
List {
ForEach(groupedData.keys.sorted(), id: \.self) { key in
Section(header: Text(key)) {
ForEach(groupedData[key]!) { item in
Text(item.title)
}
}
}
}
Styles de List : SwiftUI fournit plusieurs styles intégrés via le modificateur .listStyle(). .insetGrouped — standard pour iOS Settings, .plain — minimaliste, .inset — avec retrait, .sidebar — pour Sidebar sur iPad.
Selon SwiftUI Cookbook (2024), Section avec des sections dynamiques et ForEach à l'intérieur est un modèle standard pour regrouper des données dans des applications à structure complexe. La règle clé : n'imbriquez pas Section dans Section, et n'utilisez pas l'initialiseur List(data:) avec Section — utilisez ForEach à l'intérieur du corps de List.
.swipeActions(edge:allowsFullSwipe:content:) — un modificateur pour iOS 15+ qui ajoute des actions de balayage aux lignes de List. Permet d'afficher des boutons lors du balayage vers la gauche (par défaut) ou vers la droite, avec différentes couleurs et rôles (destructive, cancel).
struct TaskList: View {
@Binding var tasks: [Task]
var body: some View {
List {
ForEach($tasks) { $task in
Text(task.title)
.swipeActions(edge: .trailing) {
Button("Supprimer", role: .destructive) {
tasks.removeAll { $0.id == task.id }
}
}
.swipeActions(edge: .leading) {
Button(task.isDone ? "Annuler" : "Terminé") {
task.isDone.toggle()
}
.tint(.green)
}
}
}
.refreshable {
// Chargement de données asynchrone
await loadTasks()
}
}
}
.refreshable — un modificateur pour iOS 15+ qui ajoute le pull-to-refresh. Accepte une closure asynchrone qui s'exécute lorsque l'utilisateur tire la liste vers le bas. SwiftUI affiche automatiquement un indicateur de chargement. Une fois l'opération terminée, l'indicateur est masqué.
.onDelete et .onMove — des modificateurs pour iOS 13+ qui ajoutent la prise en charge de la suppression et du réordonnancement des lignes. Pour les utiliser, enveloppez les données dans ForEach avec Binding ou passez des closures via .onDelete(perform:) sur List ou ForEach.
Les performances de List dépendent du nombre de lignes, de la complexité de chaque cellule et de la fréquence des mises à jour de données. SwiftUI utilise le lazy-loading et la réutilisation des cellules (similaire à UITableView.dequeueReusableCell), mais des optimisations supplémentaires peuvent être nécessaires pour les listes de 500+ lignes.
| Optimisation | Description | Version iOS |
|---|---|---|
| Identifiable | IDs uniques pour chaque élément | iOS 13+ |
| EquatableView | Évite le redessin lorsque les données sont égales | iOS 13+ |
| id(_:) | Force la recréation de la View lors du changement d'ID | iOS 13+ |
| .equatable() | Comparaison stricte par Equatable | iOS 15+ |
| Diffable data | Diff automatique lors des changements | iOS 15+ |
Problème 1 : Mises à jour fréquentes. Si les données de la liste sont mises à jour fréquemment (par exemple, chaque seconde), List peut redessiner les cellules visibles à chaque changement d'état. Solution : utilisez des structures (value types) pour les données — SwiftUI les compare par valeur et ne redessine que les lignes modifiées.
Problème 2 : Cellules lourdes. Si chaque ligne contient une hiérarchie de Views complexe, des images et des animations, le défilement peut ralentir. Solution : extrayez les cellules dans des Views séparées, utilisez EquatableView pour éviter les redessins inutiles. Selon SwiftUI Lab (2024), diviser une ligne complexe en sous-composants réduit le temps de rendu de 30 à 50 %.
Problème 3 : Grand nombre de lignes. Avec 1000+ lignes, List fonctionne toujours efficacement grâce au lazy-loading, mais le chargement initial peut ralentir en raison du calcul de la mise en page. Solution : utilisez LazyVStack uniquement pour les listes avec des lignes uniformes où les fonctionnalités de List (balayage, sections) ne sont pas nécessaires. Pour les listes complètes, List reste le meilleur choix.
Foire aux questions
List est une View conteneur pour afficher une liste de données défilable dans SwiftUI. C'est l'équivalent de UITableView dans UIKit avec une API déclarative. Prend en charge les sections, les actions de balayage, le pull-to-refresh, l'édition et la personnalisation via .listStyle().
List utilise le lazy-loading et la réutilisation des cellules — les cellules sont créées au fur et à mesure du défilement. ScrollView + VStack crée toutes les Views à la fois. Pour les listes de 50+ lignes, List est préférable. Pour les petits ensembles fixes (jusqu'à 20 éléments), la différence est négligeable.
Utilisez le modificateur .refreshable (iOS 15+). Passez une closure asynchrone avec la logique de mise à jour des données. SwiftUI affiche automatiquement un indicateur de chargement et le masque une fois l'opération asynchrone terminée.
Utilisez Section View avec un en-tête et un footer optionnel. Placez les lignes de la liste à l'intérieur de Section. Pour les sections dynamiques, utilisez ForEach avec groupedData. Le style de la liste est configuré via .listStyle(.insetGrouped) pour une apparence similaire à iOS.
Utilisez des structures (value types) pour les données, extrayez les cellules complexes dans des Views séparées avec EquatableView, évitez les mises à jour d'état fréquentes dans chaque ligne. Pour les listes de 1000+ lignes, envisagez LazyVStack si les fonctionnalités de List ne sont pas nécessaires.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi