Annett Schwarze
Annett Schwarze

Reputation: 138

ScrollViewReader scrollTo not working in Form when .id() is used inside VStack

When using a Form and embedding the items in the form in VStacks, ScrollViewReader's scrollTo(...) is not working. Without the VStacks it does. Is there a solution while keeping the VStacks?

Sample code:

import SwiftUI

struct FormScrollVStackView: View {
    @State var useVStack = false
    var body: some View {
        VStack(spacing: 16) {
            Text("Form Scroll VStack").font(.largeTitle)
            Toggle("Use VStack", isOn: $useVStack).frame(maxWidth: 200)
            ScrollViewReader { proxy in
                Form {
                    ForEach(0..<10) { i in
                        if useVStack {
                            VStack {
                                Text("Item #\(i)").id(i).frame(height: 44)
                            }
                        } else {
                            Text("Item #\(i)").id(i).frame(height: 44)
                        }
                    }
                }
                .overlay(alignment: .top) {
                    HStack {
                        ForEach(0..<10) { i in
                            Button(action: {
                                withAnimation {
                                    proxy.scrollTo(i, anchor: .center)
                                }
                            }, label: { Text("#\(i)") })
                        }
                    }
                    .padding(4)
                    .background { Color.yellow }
                    .border(Color.blue, width: 1)
                }
            } // ... ScrollViewReader
        } // ... VStack
    } // ... body
}

#Preview {
    FormScrollVStackView()
}

Easier to test in landscape mode, preview is enough. When activating the "Use VStack" toggle and tapping on the buttons, the scrollTo is not causing a scroll. A screenshot of how the view looks:

iPhone in landscape orientation

Is there a solution apart from applying .id() to the VStacks? Is there an explanation, why it does not work?

(Xcode 15.4)


Edit:

Interestingly the issue occurs with a Form, but not with a ScrollView. If you replace Form { ... } with ScrollView { ... }.frame(maxWidth: .infinity) the scrolling works with and without the VStacks.

Upvotes: 0

Views: 70

Answers (1)

sonle
sonle

Reputation: 9161

It makes sense. The ScrollView recognizes the outermost view ID to .scrollTo.

Scans all scroll views contained by the proxy for the first with a child view with identifier id, and then scrolls to that view.

So the correct way is:

VStack {
    Text("Item #\(i)").frame(height: 44)
}
.id(i) //<- here

Upvotes: 0

Related Questions