The following code contains a list of text and a button to add more texts. When an item is added, the scroll view should scroll to the second to last (for simplicity in this example) item.
import SwiftUI
struct ContentView: View {
@StateObject private var viewModel = ViewModel()
var body: some View {
createView()
}
private func createView() -> some View {
return VStack {
ScrollView {
ScrollViewReader { scrollProxy in
VStack {
ForEach(viewModel.ids, id: \.self) { id in
Text(viewModel.texts[id]!)
.padding()
}
}.onAppear {
viewModel.scrollProxy = scrollProxy
}
}
}
Button("Add") {
viewModel.onAdd()
}.padding()
}
}
}
class ViewModel: ObservableObject {
@Published var ids: [UUID]
@Published var texts: [UUID: String]
@Published var responderID: UUID?
var scrollProxy: ScrollViewProxy?
init() {
let id = UUID()
self.ids = [id]
self.texts = [id: "0"]
}
func onAdd() {
let lastID = ids[ids.count - 1]
// create new block
let newID = UUID()
ids.append(newID)
self.texts[newID] = String(ids.count)
withAnimation {
scrollProxy?.scrollTo(lastID)
}
}
}
When tapping the button slowly, the scroll animation works fine.
But when the button is tapped quickly, the animation is ... broken? The animation slows to a crawl, taking a long time to complete.
So my question is, is there another way to animation the scrolling? I've tried using CADisplayLink, but the result is also pretty bad...