See example code below:
struct TestView: View {
var body: some View {
ScrollViewReader { proxy in
List {
ForEach(1...30, id: \.self) { item in
Text("\(item)")
.id(item)
}
}
.onAppear {
proxy.scrollTo(8, anchor: .topLeading)
}
}
}
}
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink("test") {
TestView()
}
}
}
}
Two observations:
If I don't put the
TestView
inNavigationLink
(for example, put it directly inContentView
), the code works fine.The following diff works around the issue:
.onAppear { - proxy.scrollTo(8, anchor: .topLeading) + DispatchQueue.main.async() { + proxy.scrollTo(8, anchor: .topLeading) + } }
Does anyone know what's the root cause? The workaround suggests it's a timing issue, which explains my observation 1, where there is no navigation animation. So, is it because, when the onAppear()
is run, the animation is still ongoing and hence proxy.scrollTo()
fails silently? But if so, shouldn't Apple provide a version of onAppear()
which is run after animation is done? The current workaround looks too hacky. I found it on the net and there are different versions, some using async()
, some using asyncAfter()
, which suggests none is reliable.