List ist ein Container-View in SwiftUI zum Anzeigen von Daten als vertikal scrollbare Liste, analog zu UITableView in UIKit. Laut Apple Developer Documentation, 2024 unterstützt List statische und dynamische Abschnitte, Wischaktionen, Zeilenneuanordnung und Pull-to-Refresh. Im Gegensatz zu UITableView verwendet List eine deklarative API basierend auf SwiftUI und ForEach und verwaltet automatisch die Wiederverwendung von Zellen und die Leistung bei einer großen Anzahl von Zeilen.
Wichtige Erkenntnisse
List ist ein View, das eine Sequenz von Elementen in einer vertikal scrollbaren Liste anzeigt. Es wurde in iOS 13 zusammen mit SwiftUI eingeführt und ist die primäre Methode zum Anzeigen von Datenlisten, die UITableView aus UIKit ersetzt. List verwaltet automatisch die Wiederverwendung von Zellen, das Scrollen und die Leistung.
List verwendet Lazy-Loading: Zellen werden beim Scrollen erstellt, nicht alle auf einmal. Dies unterscheidet es von VStack mit ForEach innerhalb von ScrollView, wo alle Zellen zum Renderzeitpunkt erstellt werden. List bietet auch integrierte Unterstützung für Wischaktionen, Pull-to-Refresh, Bearbeitung (Löschen/Verschieben) und Zeilenauswahl.
Laut Apple WWDC 2021 (Session 10072) erhielt List in iOS 15+ dank eines neuen Diffing-Mechanismus auf Sammlungsebene erhebliche Leistungsverbesserungen. Dies machte List beim Aktualisieren von Daten effizienter, insbesondere für Listen mit Hunderten von Zeilen.
Entwickler wählen oft zwischen List und ScrollView mit VStack zum Anzeigen einer Gruppe von Views. Der Hauptunterschied: List verwendet Zellenwiederverwendung (wie UITableView), während ScrollView + VStack alle Views sofort erstellt. Für Listen mit fester Größe (bis zu 20 Elementen) ist der Unterschied vernachlässigbar. Für dynamische Listen mit 50+ Zeilen ist List aus Leistungsgründen vorzuziehen.
Statische Liste ist eine Liste mit einer festen Anzahl von Zeilen, die direkt im List-Body angegeben werden. Sie wird für Menüs, Einstellungen und Formulare mit einem bekannten Satz von Elementen verwendet. Jede Zeile wird explizit ohne Schleifen oder ForEach deklariert.
// Statische Liste (für Menüs und Einstellungen)
List {
Text("Profil")
Text("Einstellungen")
Text("Über")
}
// Dynamische Liste (für Daten)
struct UserList: View {
let users: [User]
var body: some View {
List(users) { user in
HStack {
Text(user.name)
Text(user.role)
.foregroundColor(.secondary)
}
}
}
}
Dynamische Liste verwendet den Initialisierer List(data:rowContent:) oder ForEach innerhalb des List-Body. Der erste Ansatz ist praktisch, wenn jede Zeile einem Datenelement entspricht. Der zweite ist nützlich, wenn es Abschnitte oder zusätzliche Elemente zwischen den Daten gibt.
Identifikation (Identifiable): Für dynamische Listen müssen Datenelemente dem Identifiable-Protokoll entsprechen, oder Sie müssen einen KeyPath zu einer eindeutigen Kennung im data:id-Tupel angeben. SwiftUI verwendet Kennungen, um Änderungen zu verfolgen: Hinzufügen, Löschen und Verschieben von Zeilen.
Section ist ein View zum Gruppieren von Zeilen in einer List mit einer Überschrift und einem optionalen Footer. Section akzeptiert header und footer als ViewBuilder, sodass nicht nur Text, sondern auch benutzerdefinierte Views für Abschnittsüberschriften verwendet werden können.
struct SettingsView: View {
var body: some View {
List {
Section(header: Text("Konto")) {
Text("Name")
Text("E-Mail")
}
Section(header: Text("Benachrichtigungen")) {
Toggle("Push", isOn: $pushEnabled)
Toggle("Email", isOn: $emailEnabled)
}
}
.listStyle(.insetGrouped)
}
}
// Dynamische Abschnitte mit ForEach
List {
ForEach(groupedData.keys.sorted(), id: \.self) { key in
Section(header: Text(key)) {
ForEach(groupedData[key]!) { item in
Text(item.title)
}
}
}
}
List-Stile: SwiftUI bietet mehrere integrierte Stile über den Modifikator .listStyle(). .insetGrouped — Standard für iOS Settings, .plain — minimalistisch, .inset — mit Einzug, .sidebar — für Sidebar auf dem iPad.
Laut SwiftUI Cookbook (2024) ist Section mit dynamischen Abschnitten und ForEach darin ein Standardmuster zum Gruppieren von Daten in Anwendungen mit komplexer Struktur. Die Hauptregel: Verschachteln Sie Section nicht in Section und verwenden Sie den Initialisierer List(data:) nicht zusammen mit Section — verwenden Sie ForEach innerhalb des List-Body.
.swipeActions(edge:allowsFullSwipe:content:) — ein Modifikator für iOS 15+, der Wischaktionen zu List-Zeilen hinzufügt. Ermöglicht das Anzeigen von Schaltflächen beim Wischen nach links (Standard) oder rechts, mit verschiedenen Farben und Rollen (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("Löschen", role: .destructive) {
tasks.removeAll { $0.id == task.id }
}
}
.swipeActions(edge: .leading) {
Button(task.isDone ? "Rückgängig" : "Fertig") {
task.isDone.toggle()
}
.tint(.green)
}
}
}
.refreshable {
// Asynchrones Datenladen
await loadTasks()
}
}
}
.refreshable — ein Modifikator für iOS 15+, der Pull-to-Refresh hinzufügt. Akzeptiert einen asynchronen Closure, der ausgeführt wird, wenn der Benutzer die Liste nach unten zieht. SwiftUI zeigt automatisch einen Ladeindikator an. Nach Abschluss des Vorgangs wird der Indikator ausgeblendet.
.onDelete und .onMove — Modifikatoren für iOS 13+, die Unterstützung zum Löschen und Neuanordnen von Zeilen hinzufügen. Um sie zu verwenden, umschließen Sie die Daten in ForEach mit Binding oder übergeben Sie Closures über .onDelete(perform:) an List oder ForEach.
Die List-Leistung hängt von der Anzahl der Zeilen, der Komplexität jeder Zelle und der Häufigkeit der Datenaktualisierungen ab. SwiftUI verwendet Lazy-Loading und Zellenwiederverwendung (ähnlich UITableView.dequeueReusableCell), aber für Listen mit 500+ Zeilen können zusätzliche Optimierungen erforderlich sein.
| Optimierung | Beschreibung | iOS-Version |
|---|---|---|
| Identifiable | Eindeutige IDs für jedes Element | iOS 13+ |
| EquatableView | Vermeidet Neulackieren bei gleichen Daten | iOS 13+ |
| id(_:) | Erzwingt View-Neuerstellung bei ID-Änderung | iOS 13+ |
| .equatable() | Strikter Vergleich mittels Equatable | iOS 15+ |
| Diffable data | Automatischer Diff bei Änderungen | iOS 15+ |
Problem 1: Häufige Aktualisierungen. Wenn die Daten in der Liste häufig aktualisiert werden (z.B. jede Sekunde), kann List die sichtbaren Zellen bei jeder Statusänderung neu zeichnen. Lösung: Verwenden Sie Strukturen (Wertetypen) für die Daten — SwiftUI vergleicht sie nach Wert und zeichnet nur geänderte Zeilen neu.
Problem 2: Schwere Zellen. Wenn jede Zeile eine komplexe View-Hierarchie, Bilder und Animationen enthält, kann das Scrollen langsamer werden. Lösung: Extrahieren Sie Zellen in separate Views, verwenden Sie EquatableView, um unnötige Neuzeichnungen zu vermeiden. Laut SwiftUI Lab (2024) reduziert die Aufteilung einer komplexen Zeile in Unterkomponenten die Renderzeit um 30–50%.
Problem 3: Große Anzahl von Zeilen. Bei 1000+ Zeilen arbeitet List dank Lazy-Loading immer noch effizient, aber das anfängliche Laden kann aufgrund der Layoutberechnung langsamer sein. Lösung: Verwenden Sie LazyVStack nur für Listen mit einheitlichen Zeilen, bei denen List-Funktionen (Wischen, Abschnitte) nicht benötigt werden. Für voll funktionsfähige Listen bleibt List die beste Wahl.
Häufig gestellte Fragen
List ist ein Container-View zum Anzeigen einer scrollbaren Datenliste in SwiftUI. Es ist das Äquivalent zu UITableView in UIKit mit einer deklarativen API. Unterstützt Abschnitte, Wischaktionen, Pull-to-Refresh, Bearbeitung und Anpassung über .listStyle().
List verwendet Lazy-Loading und Zellenwiederverwendung — Zellen werden beim Scrollen erstellt. ScrollView + VStack erstellt alle Views auf einmal. Für Listen mit 50+ Zeilen ist List vorzuziehen. Für feste kleine Sets (bis zu 20 Elemente) ist der Unterschied vernachlässigbar.
Verwenden Sie den Modifikator .refreshable (iOS 15+). Übergeben Sie einen asynchronen Closure mit der Datenaktualisierungslogik. SwiftUI zeigt automatisch einen Ladeindikator an und blendet ihn nach Abschluss des asynchronen Vorgangs aus.
Verwenden Sie Section View mit einer Überschrift und einem optionalen Footer. Platzieren Sie Listenzeilen innerhalb von Section. Für dynamische Abschnitte verwenden Sie ForEach mit groupedData. Der Listenstil wird über .listStyle(.insetGrouped) für ein iOS-ähnliches Erscheinungsbild konfiguriert.
Verwenden Sie Strukturen (Wertetypen) für Daten, extrahieren Sie komplexe Zellen in separate Views mit EquatableView, vermeiden Sie häufige Statusaktualisierungen in jeder Zeile. Für Listen mit 1000+ Zeilen ziehen Sie LazyVStack in Betracht, wenn List-Funktionen nicht benötigt werden.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch