List — контейнерно View в SwiftUI за показване на данни под формата на вертикално превъртащ се списък, аналог на UITableView в UIKit. Според Apple Developer Documentation, 2024, List поддържа статични и динамични секции, действия за плъзгане, преместване на редове и pull-to-refresh. За разлика от UITableView, List използва декларативен API, базиран на SwiftUI и ForEach, като автоматично управлява повторното използване на клетки и производителността при голям брой редове.
Основни точки
List — View, което показва последователност от елементи във вертикално превъртащ се списък. Появи се в iOS 13 заедно със SwiftUI и е основният начин за показване на списъци с данни, замествайки UITableView от UIKit. List автоматично управлява повторното използване на клетки, превъртането и производителността.
List използва lazy-loading: клетките се създават при превъртане, а не всички наведнъж. Това го отличава от VStack с ForEach вътре в ScrollView, където всички клетки се създават при рендиране. List също предоставя вградена поддръжка за действия за плъзгане, pull-to-refresh, редактиране (изтриване/преместване) и избор на редове.
Според Apple WWDC 2021 (Session 10072), List в iOS 15+ получи значителни подобрения на производителността благодарение на нов механизъм за diffing на ниво колекции. Това направи List по-ефективен при актуализиране на данни, особено за списъци със стотици редове.
Разработчиците често избират между List и ScrollView с VStack за показване на набор от Views. Ключовата разлика: List използва повторно използване на клетки (като UITableView), докато ScrollView + VStack създава всички Views наведнъж. За списъци с фиксиран брой елементи (до 20) разликата е незначителна. За динамични списъци с 50+ редове List е за предпочитане от гледна точка на производителност.
Статичен List — списък с фиксиран брой редове, зададени директно в тялото на List. Използва се за менюта, настройки и формуляри с известен набор от елементи. Всеки ред се декларира изрично, без цикли или ForEach.
// Статичен списък (за менюта и настройки)
List {
Text("Профил")
Text("Настройки")
Text("Относно")
}
// Динамичен списък (за данни)
struct UserList: View {
let users: [User]
var body: some View {
List(users) { user in
HStack {
Text(user.name)
Text(user.role)
.foregroundColor(.secondary)
}
}
}
}
Динамичен List използва инициализатора List(data:rowContent:) или ForEach вътре в тялото на List. Първият вариант е удобен, когато всеки ред съответства на един елемент данни. Вторият — когато има секции или допълнителни елементи между данните.
Идентификация (Identifiable): За динамични списъци елементите данни трябва да съответстват на протокола Identifiable или в кортежа data:id трябва да се посочи KeyPath към уникален идентификатор. SwiftUI използва идентификатори за проследяване на промени: добавяне, изтриване и преместване на редове.
Section — View за групиране на редове в List със заглавие и опционален footer. Section приема header и footer като ViewBuilder, позволявайки използването не само на текст, но и на персонализирани Views за заглавия на секции.
struct SettingsView: View {
var body: some View {
List {
Section(header: Text("Акаунт")) {
Text("Име")
Text("Имейл")
}
Section(header: Text("Известия")) {
Toggle("Push", isOn: $pushEnabled)
Toggle("Email", isOn: $emailEnabled)
}
}
.listStyle(.insetGrouped)
}
}
// Динамични секции с ForEach
List {
ForEach(groupedData.keys.sorted(), id: \.self) { key in
Section(header: Text(key)) {
ForEach(groupedData[key]!) { item in
Text(item.title)
}
}
}
}
Стилове на List: SwiftUI предоставя няколко вградени стила чрез модификатора .listStyle(). .insetGrouped — стандартен за iOS Settings, .plain — минималистичен, .inset — с отстъпи, .sidebar — за Sidebar на iPad.
Според SwiftUI Cookbook (2024), Section с динамични секции и ForEach вътре е стандартен модел за групиране на данни в приложения със сложна структура. Ключово правило: не влагайте Section вътре в Section и не използвайте инициализатора List(data:) заедно с Section — използвайте ForEach вътре в тялото на List.
.swipeActions(edge:allowsFullSwipe:content:) — модификатор за iOS 15+, който добавя действия за плъзгане към редовете на List. Позволява показване на бутони при плъзгане наляво (по подразбиране) или надясно, с различни цветове и роли (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("Изтрий", role: .destructive) {
tasks.removeAll { $0.id == task.id }
}
}
.swipeActions(edge: .leading) {
Button(task.isDone ? "Отмени" : "Готово") {
task.isDone.toggle()
}
.tint(.green)
}
}
}
.refreshable {
// Асинхронно зареждане на данни
await loadTasks()
}
}
}
.refreshable — модификатор за iOS 15+, който добавя pull-to-refresh. Приема асинхронно затваряне (async), което се изпълнява, когато потребителят издърпа списъка надолу. SwiftUI автоматично показва индикатор за зареждане. След завършване на операцията индикаторът се скрива.
.onDelete и .onMove — модификатори за iOS 13+, които добавят поддръжка за изтриване и преместване на редове. За да ги използвате, увийте данните в ForEach с Binding или предайте затваряния чрез .onDelete(perform:) на List или ForEach.
Производителността на List зависи от броя редове, сложността на всяка клетка и честотата на актуализации на данни. SwiftUI използва lazy-loading и повторно използване на клетки (подобно на UITableView.dequeueReusableCell), но допълнителни оптимизации може да са необходими за списъци с 500+ редове.
| Оптимизация | Описание | iOS версия |
|---|---|---|
| Identifiable | Уникално ID за всеки елемент | iOS 13+ |
| EquatableView | Избягва пререндиране при равни данни | iOS 13+ |
| id(_:) | Принудително пресъздаване на View при промяна на ID | iOS 13+ |
| .equatable() | Сравнение стриктно по Equatable | iOS 15+ |
| Diffable data | Автоматичен diff при промени | iOS 15+ |
Проблем 1: чести актуализации. Ако данните в списъка се актуализират често (например всяка секунда), List може да пререндира видимите клетки при всяка промяна на състоянието. Решение: използвайте структури (value types) за данни — SwiftUI ги сравнява по стойност и пререндира само променените редове.
Проблем 2: тежки клетки. Ако всеки ред съдържа сложна йерархия от Views, изображения и анимации, превъртането може да бъде бавно. Решение: преместете клетките в отделни Views, използвайте EquatableView за предотвратяване на ненужно пререндиране. Според SwiftUI Lab (2024), разделянето на сложен ред на подкомпоненти намалява времето за рендиране с 30–50%.
Проблем 3: голям брой редове. При 1000+ редове List все още работи ефективно благодарение на lazy-loading, но първоначалното зареждане може да се забави поради изчисляване на layout. Решение: използвайте LazyVStack само за списъци с еднотипни редове, където не са необходими функциите на List (плъзгане, секции). За напълно функционални списъци List остава най-добрият избор.
Често задавани въпроси
List — контейнерно View за показване на превъртащ се списък с данни в SwiftUI. Аналог на UITableView в UIKit с декларативен API. Поддържа секции, действия за плъзгане, pull-to-refresh, редактиране и персонализиране чрез .listStyle().
List използва lazy-loading и повторно използване на клетки — клетките се създават при превъртане. ScrollView + VStack създава всички Views наведнъж. За списъци с 50+ редове List е за предпочитане. За фиксирани малки набори (до 20 елемента) разликата е незначителна.
Използвайте модификатора .refreshable (iOS 15+). Предайте асинхронно затваряне с логика за актуализиране на данни. SwiftUI автоматично показва индикатор за зареждане и го скрива след завършване на асинхронната операция.
Използвайте Section View с header и опционален footer. Поставете редовете на списъка вътре в Section. За динамични секции използвайте ForEach с groupedData. Стилът на списъка се конфигурира чрез .listStyle(.insetGrouped) за iOS-подобен вид.
Използвайте структури (value types) за данни, преместете сложните клетки в отделни Views с EquatableView, избягвайте чести актуализации на състоянието във всеки ред. За списъци с 1000+ редове обмислете LazyVStack, ако не са необходими функциите на List.
Обобщение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също