I have a list wrapped in a ScrollViewReader and have overlayed a button (updated to provide a complete demo)
struct Rows: View {
var dataRows: [RowData] = []
init() {
for i in 0...1000 {
dataRows.append(RowData(id: i))
}
}
var body: some View {
ScrollViewReader { scrollView in
ZStack(alignment: .bottomTrailing) {
List(dataRows) { row in
NavigationLink {
} label: {
Row(data: row)
}
}
Button("Scroll To Top") {
print("button pressed")
scrollView.scrollTo(0)
}
.buttonStyle(.bordered)
}
}
}
}
struct Row: View {
var data: RowData
var body: some View {
Text(String(data.id))
}
}
struct RowData: Identifiable {
var id: Int
}
This all works as expected, I tap the button and the list is scrolled to row with id 0
However if I flick the list, it scrolls and slowly decelerates over several seconds, during the time if I press the button the message is printed, but the list doesn't scroll back.
scrollTo only seems to work if the list has come to a complete stop
How can I halt the scrolling to get the button to work?
I can reproduce this in the simulator, but it sometimes works as I'd like - however on a real device (iPhone 12, iOS 17) the problem is always seen
Many thanks!
I don't think this is the clearest solution, but we can create additional @State
variable and use it with .onChange
modifier.
struct ContentView: View {
@State private var shouldScrollToItem = false
var body: some View {
ScrollViewReader { scrollViewProxy in
ScrollView {
Button("Scroll") {
shouldScrollToItem.toggle()
}
...
}
.onChange(of: shouldScrollToItem) {
scrollViewProxy.scrollTo(id)
}
}
}
}