Related Post: Keep ScrollView position when adding items on the top
I was trying to implement a message view using ScrollView + LazyVStack. This view requires pagination so I used onScrollTargeVisibilityChange modifier to detect if the first item appears on screen and a new page needs to be loaded. I learnt from the above post that scrollPositon modifier can help keep the scroll position. I tested the method mentioned in that post -- use a button to add new items to the top -- and it worked.
However, when use onScrollTargeVisibilityChange modifier to add items, the view automatically scrolls to the top and cause the following loop:
first item in the list appears on screen --> load and insert more items to the top --> scroll view scrolls to top --> first item appears --> load more data --> scroll to top --> first item ... --> more data... --> top ...
Until it generates the error ScrollTargetVisibilityChange tried to update multiple times per frame.
Here is the simplified code.
struct Item: Identifiable {
var id: UUID = .init()
var content: String
}
struct ScrollViewTest: View {
@State private var items: [Item] = (0...30).map {Item(content:"\($0)")}.reversed()
@State private var itemID: Item.ID?
@State private var page: Int = 0
var body: some View {
ScrollView {
LazyVStack {
ForEach(items) {item in
Text(item.content)
.frame(height: 30)
}
}
.scrollTargetLayout()
}
.scrollPosition(id: $itemID)
.defaultScrollAnchor(.bottom)
.onScrollTargetVisibilityChange(idType: Item.ID.self) { onScreenItemIDs in
if onScreenItemIDs.first == items.first?.id {
page += 1
let newItems = (page*30+1 ... (page+1)*30).map {Item(content:"\($0)")}
items.insert(contentsOf: newItems.reversed(), at: 0)
}
}
.toolbar {
Button("Add") {
page += 1
let newItems = (page*30+1 ... (page+1)*30).map {Item(content:"\($0)")}
items.insert(contentsOf: newItems.reversed(), at: 0)
}
}
}
}
I want to load data while scrolling without the need of pressing any buttons. How can I solve this problem?