SwiftUI 2.0 introduces LazyVStack and LazyHStack, which only render Views when they are within the visible area. This significantly improves app performance. The efficiency issues caused by VStack or HStack have been briefly compared in the article SwiftUI List (3) - List, Form, VStack.
Basic Usage
Swift
struct LazyStack: View {
var body: some View {
ScrollView{
LazyVStack{ // Replace with VStack for a comparison of when new data is created
ForEach(0...1000, id: \.self){ id in
Text(LazyItem(id: id).title)
}
}
}
}
}
struct LazyItem{
let id: Int
let title: String
init(id: Int){
self.id = id
self.title = "id: \(id)"
print("init new object: \(id)")
}
}
Using Lazy Feature to Create Continuous List Display
Swift
import SwiftUI
struct LazyStack: View {
@State var list = (0...40).map{ _ in Item(number: Int.random(in: 1000...5000)) }
@State var loading = false
var body: some View {
VStack{
Text("count: \(list.count)")
// Data count. Under LazyVStack, data increases each refresh. Under VStack, data continuously increases.
ScrollView{
LazyVStack{ // Replace with VStack for comparison
ForEach(list, id: \.id){ item in
Text("id: \(item.number)")
.onAppear {
moreItem(id: item.id)
}
}
}
if loading {
ProgressView()
}
}
}
}
func moreItem(id: UUID){
// If it's the last data, then fetch new data
if id == list.last!.id && !loading {
loading = true
// Add delay to simulate asynchronous data fetching
DispatchQueue.main.asyncAfter(deadline: .now() + 1){
// Data simulation, can also fetch from the network
list.append(contentsOf: (0...30).map{ _ in Item(number: Int.random(in: 1000...5000)) })
loading = false
}
}
}
}
struct Item: Identifiable{
let id = UUID()
let number: Int
}
The usage of LazyHStack is similar to LazyVStack.