SwiftUI: List or LazyVStack? đŸ€”SwipeActions for any views?

Alex Kraev
3 min readMay 13, 2023

--

List or LazyVStack? Which one is best to use and when?

It depends, of coz, on the task. For example, if the app based on on UIKit, and you want to add SwiftUI, then you should be considered that the separators between cells in the List, if they are not needed, are removed in a very “crutch” way before iOS 15:

.onAppear {
UITableView.appearance().separatorStyle = .none
}

This can affect the design of the UITableView throughout the whole application. Beginning with iOS 15 a special modifier .listRowSeparator(.hidden) has already appeared for this.

One of the main key features is the difference in the rendering (which depend on iOS versions) of List and LazyVStack. In iOS < 15 List renders cells “with a margin”, namely, if the List is stretched to full screen, then the first 15 (iPhone 6s) — 20 elements do not have lazy loading, and it doesn’t matter what the element’s frame height is. Opp, LazyVStack renders only elements that are visible on the screen. Thus, for example, by setting the .onAppear{
} modifier, we get the expected behavior only for LazyVStack.

Gist for this code is here

Beginning with iOS 15 List renders only items that are visible on the screen. Turns out that in iOS < 15 using List pagination can only be done if you should load > 20 items. This may not suit for everyone and LazyVStack should be used.

The other problem for List is that cells are really slightly customizable. Even so List has a big advantage in swipeActions. Actually this method is available from iOS 15. But is it possible to get power of swipeActions for LazyVStack cells? Yep, sure, and not only for LazyVStack but even for any view! You can simply use this package! Moreover you can use it in project targeting iOS 13. Quick start is here.

The process for adding SwipeActions is quite simple so I’ll just provide an example of the code:

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) { // đŸ‘ˆđŸ» LOOK HERE
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)

}
}
}
}
}
}

The result will be:

That’s all!âœŒđŸ» Don’t forget to subscribe me on github and to my Telegram channel dedicated to mobile development.

--

--

Alex Kraev

Mobile engineer | IT lead | Writer | Open Source author from Moscow, like Swift, SwiftUI, Kotlin, Jetpack, subscribe to my channel: https://t.me/swiftui_dev