Calling scrollTo() in onAppear() doesn't always work

1.3k views Asked by At

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:

  1. If I don't put the TestView in NavigationLink (for example, put it directly in ContentView), the code works fine.

  2. 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.

0

There are 0 answers