Why Is The Swiftui List Not Lazy (Compared to Lazyvstack)

iOS SwiftUI - Difference between LazyVStack and LazyVGrid

The difference between LazyVGrid and LazyVStack is the container type.

Both of these containers provide lazy loading which improves the performance of your app, but the main difference is how it stores its child views.

LazyVStack displays its child views from top to bottom in a vertical alignment. It’s similar to a single line.

LazyVGrid displays its child views as rows and columns. It’s similar to a chess board.

Base on your desired design, LazyVStack should be more suitable since it contains many components and texts.

However, if you are going to just display thousands of image without much detail; similar to Gallery, then LazyVGrid should be your first choice, plus it provides a great readability for users too.

SwiftUI LazyVStack vs UITableView CPU Usage

@hyouuu The most important part is the progress value. Avoid using the @Published value as much as possible in ViewModels. Instead, split the views into subviews and manually set a value to the ViewModel as in the example.

import SwiftUI
import Combine

final class ViewModel: ObservableObject {

var array = Array(1...1000)
var text = "Hello, world!"

var progress: Double = 0.0 {
didSet {
print("new value",progress)
}
}
}

struct ContentView: View {

@StateObject var viewModel = ViewModel()

var body: some View {
VStack {
Scroll(viewModel: viewModel)
Slide(viewModel: viewModel)
}
}
}

struct Scroll: View {

@StateObject var viewModel: ViewModel

var body: some View {
List {
ForEach(viewModel.array, id: \.self) { value in Text(viewModel.text) }
}
}
}

struct Slide: View {

@StateObject var viewModel: ViewModel
@State var progress:Double = 0.0

var body: some View {
Slider(value: $progress, in: 0.0...1.0, step: 0.01)
.onChange(of: progress) { newValue in
viewModel.progress = newValue
}
}
}

LazyVStack Initializes all views when one changes SwiftUI

Here is a working code, there is some points to mention, View in SwiftUI would get initialized here and there or anytime SwiftUI thinks it needed! But the body of View would get computed if really some value in body changed. It is planed to work like that, there is some exceptions as well. Like body get computed even the values that used in the body were as before with no change, I do not want inter to that topic! But in your example and in your issue, we want SwiftUI renders only the changed View, for this goal the down code works well without issue, but as you can see I used VStack, if we change VStack to LazyVStack, SwiftUI would renders some extra view due its undercover codes, and if you scroll to down and then to up, it would forget all rendered view and data in memory and it will try to render the old rendered views, so it is the nature of LazyVStack, we cannot do much about it. Apple want LazyVStack be Lazy. But you can see that LazyVStack would not render all views, but some of them that needs to works. we cannot say or know how much views get rendered in Lazy way, but for sure not all of them.

let initializingArray: () -> [String] = {
var items: [String] = [String]()

for _ in 0...200 { items.append(UUID().uuidString) }

return items
}

struct ContentView: View {

@State var items: [String] = initializingArray()

var body: some View {
ScrollView {
VStack {
ForEach(items, id: \.self) { item in

Button(action: {

if let index = self.items.firstIndex(where: { $0 == item }) {
items[index] = "changed \(index)"
}

}, label: {
ItemView(item: item)
})

}
}
}

}
}

struct ItemView: View {

let item: String

var body: some View {
print("Rendering row for:", item)
return Text(item)

}
}


Related Topics



Leave a reply



Submit