List — что это, компонент списка в SwiftUI

Автор: IT Sectr Опубликовано: 2026-06-25 Время чтения: 7 мин

List — это контейнерное View в SwiftUI для отображения данных в виде вертикально прокручиваемого списка, аналог UITableView в UIKit. По данным Apple Developer Documentation, 2024, List поддерживает статические и динамические секции, свайп-действия, перетаскивание строк и pull-to-refresh. В отличие от UITableView, List использует декларативный API на основе SwiftUI и ForEach, автоматически управляя переиспользованием ячеек и производительностью при большом количестве строк.

Главное

  • List — контейнер для прокручиваемого списка данных в SwiftUI
  • ForEach — основной способ динамического отображения данных в List
  • Секции — Section View для группировки строк с заголовками
  • Свайп-действия — swipeActions для iOS 15+
  • Pull-to-refresh — .refreshable для iOS 15+

Что такое List в SwiftUI?

List — это View, отображающее последовательность элементов в вертикально прокручиваемом списке. Оно появилось в iOS 13 вместе со SwiftUI и является основным способом отображения списков данных, заменяя UITableView из UIKit. List автоматически управляет переиспользованием ячеек, скроллом и производительностью.

List использует lazy-loading: ячейки создаются по мере прокрутки, а не все сразу. Это отличает его от VStack с ForEach внутри ScrollView, где все ячейки создаются при рендеринге. List также предоставляет встроенную поддержку свайп-действий, pull-to-refresh, редактирования (delete/move) и выбора строк.

По данным Apple WWDC 2021 (Session 10072), List в iOS 15+ получил существенные улучшения производительности благодаря новому механизму diffing на уровне коллекций. Это сделало List более эффективным при обновлении данных, особенно для списков с сотнями строк.

List vs ScrollView + VStack

Разработчики часто выбирают между List и ScrollView с VStack для отображения набора View. Ключевое отличие: List использует переиспользование ячеек (как UITableView), а ScrollView + VStack создаёт все View сразу. Для списков с фиксированным количеством элементов (до 20) разница незначительна. Для динамических списков с 50+ строками List предпочтительнее по производительности.

Статические и динамические списки

Статический List — это список с фиксированным количеством строк, заданных напрямую в теле List. Используется для меню, настроек и форм с известным набором элементов. Каждая строка объявляется явно, без циклов или ForEach.

swift
// Static list (for menus and settings)
List {
    Text("Profile")
    Text("Settings")
    Text("About")
}

// Dynamic list (for data)
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, позволяя использовать не только текст, но и кастомные View для заголовков секций.

swift
struct SettingsView: View {
    var body: some View {
        List {
            Section(header: Text("Account")) {
                Text("Name")
                Text("Email")
            }
            Section(header: Text("Notifications")) {
                Toggle("Push", isOn: $pushEnabled)
                Toggle("Email", isOn: $emailEnabled)
            }
        }
        .listStyle(.insetGrouped)
    }
}

// Dynamic sections with 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.

Свайп-действия и pull-to-refresh

.swipeActions(edge:allowsFullSwipe:content:) — модификатор для iOS 15+, добавляющий свайп-действия к строкам List. Позволяет отображать кнопки при свайпе влево (default) или вправо, с разными цветами и ролями (destructive, cancel).

swift
struct TaskList: View {
    @Binding var tasks: [Task]

    var body: some View {
        List {
            ForEach($tasks) { $task in
                Text(task.title)
                    .swipeActions(edge: .trailing) {
                        Button("Delete", role: .destructive) {
                            tasks.removeAll { $0.id == task.id }
                        }
                    }
                    .swipeActions(edge: .leading) {
                        Button(task.isDone ? "Undo" : "Done") {
                            task.isDone.toggle()
                        }
                        .tint(.green)
                    }
            }
        }
        .refreshable {
            // Async data loading
            await loadTasks()
        }
    }
}

.refreshable — модификатор для iOS 15+, добавляющий pull-to-refresh. Принимает асинхронное замыкание (async), которое выполняется, когда пользователь тянет список вниз. SwiftUI автоматически отображает индикатор загрузки. После завершения операции индикатор скрывается.

.onDelete и .onMove — модификаторы для iOS 13+, добавляющие поддержку удаления и перестановки строк. Для их использования оберните данные в ForEach с Binding или передайте замыкания через .onDelete(perform:) на List или ForEach.

Производительность List и оптимизация

Производительность List зависит от количества строк, сложности каждой ячейки и частоты обновлений данных. SwiftUI использует lazy-loading и переиспользование ячеек (аналогично UITableView.dequeueReusableCell), но дополнительные оптимизации могут потребоваться для списков с 500+ строками.

ОптимизацияОписаниеiOS версия
IdentifiableУникальные ID для каждого элементаiOS 13+
EquatableViewИзбегает перерисовки при равных данныхiOS 13+
id(_:)Принудительное пересоздание View при изменении IDiOS 13+
.equatable()Сравнение строго по EquatableiOS 15+
Diffable dataАвтоматический diff при измененияхiOS 15+

Проблема 1: частые обновления. Если данные в списке обновляются часто (например, каждую секунду), List может перерисовывать видимые ячейки при каждом изменении состояния. Решение: используйте структуры (value types) для данных — SwiftUI сравнивает их по значению и перерисовывает только изменившиеся строки.

Проблема 2: тяжёлые ячейки. Если каждая строка содержит сложную иерархию View, изображения и анимации, скролл может тормозить. Решение: выносите ячейки в отдельные View, используйте EquatableView для предотвращения лишних перерисовок. По данным SwiftUI Lab (2024), разбиение сложной строки на подкомпоненты снижает время рендеринга на 30–50%.

Проблема 3: большое количество строк. При 1000+ строк List по-прежнему работает эффективно благодаря lazy-loading, но начальная загрузка может замедлиться из-за вычисления layout. Решение: используйте LazyVStack только для списков с однотипными строками, где не нужны функции List (свайпы, секции). Для полнофункциональных списков List остаётся лучшим выбором.

Часто задаваемые вопросы

Что такое List в SwiftUI?

List — контейнерное View для отображения прокручиваемого списка данных в SwiftUI. Аналог UITableView в UIKit с декларативным API. Поддерживает секции, свайп-действия, pull-to-refresh, редактирование и кастомизацию через .listStyle().

Чем List отличается от ScrollView + VStack?

List использует lazy-loading и переиспользование ячеек — ячейки создаются по мере прокрутки. ScrollView + VStack создаёт все View сразу. Для списков с 50+ строками List предпочтительнее. Для фиксированных небольших наборов (до 20 элементов) разница незначительна.

Как добавить pull-to-refresh в List?

Используйте модификатор .refreshable (iOS 15+). Передайте асинхронное замыкание с логикой обновления данных. SwiftUI автоматически отображает индикатор загрузки и скрывает его после завершения асинхронной операции.

Как сгруппировать строки в List?

Используйте Section View с header и опциональным footer. Внутри Section помещайте строки списка. Для динамических секций используйте ForEach с groupedData. Стиль списка настраивается через .listStyle(.insetGrouped) для iOS-подобного вида.

Как ускорить List с большим количеством строк?

Используйте структуры (value types) для данных, выносите сложные ячейки в отдельные View с EquatableView, избегайте частых обновлений состояния в каждой строке. Для списков с 1000+ строк рассмотрите LazyVStack, если не нужны функции List.

Итоги

  • List — контейнер для прокручиваемого списка с lazy-loading и переиспользованием ячеек
  • ForEach — основной способ динамического отображения данных в List
  • Section — группировка строк с заголовками и footer
  • swipeActions — свайп-действия для iOS 15+
  • refreshable — pull-to-refresh для iOS 15+
  • Стили — insetGrouped, plain, inset, sidebar через .listStyle()
  • Производительность — используйте Identifiable, EquatableView и value types

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также