Reputation: 138
When using a Form
and embedding the items in the form in VStack
s, ScrollViewReader
's scrollTo(...)
is not working. Without the VStack
s it does.
Is there a solution while keeping the VStack
s?
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:
Is there a solution apart from applying .id()
to the VStack
s?
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 VStack
s.
Upvotes: 0
Views: 70
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