SwiftUI: List или LazyVStack? 🤔SwipeActions для любых view?
List или LazyVStack? Что лучше использовать и когда?
Зависит, конечно, от поставленной задачи. Например, если приложение на UIKit, и хотите подтянуть SwiftUI, то необходимо учитывать, что разделители у ячеек в List, если они не нужны, до iOS 15 убираются весьма костыльным способом:
.onAppear {
UITableView.appearance().separatorStyle = .none
}
Тем самым можно зааффектить дизайн UITableView во всем приложении. В iOS 15 для этого уже появился специальный модификатор .listRowSeparator(.hidden)
.
Одной из главных особенностей является рендеринг у List и LazyVStack, который отличается в зависимости от версий iOS. В iOS < 15 List рендерит ячейки “с запасом”, а именно, если List растянут на весь экран, то ленивой загрузки нет у первых 15 (iPhone 6s) — 20 элементов, при этом без разницы, какая высота фрейма у элемента. Напротив, LazyVStack рендерит только те элементы, которые видны на экране. Таким образом, например, вешая модификатор .onAppear{..}
, мы получаем ожидаемое поведение только у LazyVStack.
Начиная с iOS 15, List рендерит уже только элементы, видимые на экране. Получается, что пагинацию на List для iOS < 15 можно сделать только, если загружать > 20 элементов. Это не всем может подойти, в приоритете окажется LazyVStack.
Другим отличием является то, что ячейки List слабо кастомизируются. Однако у List есть большое преимущество в виде swipeActions. Но этот метод доступен, только начиная с iOS 15. Но можно ли как-то использовать всю мощь swipeActions
для ячеек LazyVStack? Да! И не только для LazyVStack, а для любых вью! Добавьте себе в проект этот package! Кроме того, вы можете использовать его в проекте, ориентированном на iOS 13. Краткий мануал здесь.
Процесс добавления SwipeActions
интуитивно просто, поэтому просто приведу пример кода:
import SwipeActions
struct YourView: View {
var body: some View {
ScrollView {
LazyVStack {
ForEach(1...100, id: \.self) { cell in
Text("Cell \(cell)")
.frame(height: 50, alignment: .center)
.frame(maxWidth: .infinity)
.contentShape(Rectangle())
.addSwipeAction(edge: .trailing) { // 👈🏻 магия здесь 🙂
Button {
print("remove \(cell)")
} label: {
Image(systemName: "trash")
.foregroundColor(.white)
}
.frame(width: 60, height: 50, alignment: .center)
.contentShape(Rectangle())
.background(Color.red)
Button {
print("Inform \(cell)")
} label: {
Image(systemName: "bell.slash.fill")
.foregroundColor(.white)
}
.frame(width: 60, height: 50, alignment: .center)
.background(Color.blue)
}
}
}
}
}
}
Результатом будет:
На этом все!✌🏻
Не забывайте подписываться на github и на канал в телеграмме, посвященный мобильной разработке.