Hit this one while working on our video subtitles app Captionista once iOS 15 came out. Spooky scrolling action at a distance.
FB9697336 – ScrollViewReader scrollTo scrolls incorrectly sometimes, affected by unrelated padding
Please provide a descriptive title for your feedback:
ScrollViewReader scrollTo scrolls incorrectly sometimes, affected by unrelated padding
Which area are you seeing an issue with?
SwiftUI Framework
What type of feedback are you reporting?
Incorrect/Unexpected Behavior
Please describe the issue and what steps we can take to reproduce it:
Using the ScrollViewProxy.scrollTo function, you can get incorrect scrolling behaviour, seemingly dependent on padding applied to an ancestor of the view that is being scrolled.
Attached is a complete sample project (inline here is just the view source), and a video showing the problem.
The project should vertically scroll the tapped view to the center of the scroll view.
What actually happens is that sometimes it also scrolls horizontally, after the vertical scroll has completed.
If you remove the marked padding, it all works as expected. I’ve seen this on iOS 15 since the betas. It does not seem to happen on iOS 14 devices, even when built with Xcode 13.
The workaround is to apply the ancestor view padding to the view that is being scrolled.
import SwiftUI
struct ContentView: View {
let items: [Int] = Array(0...50)
var body: some View {
VStack {
Text("Keep tapping items to scroll them to center and it will drift to the side sometimes")
GeometryReader { geometryProxy in
ScrollViewReader { scrollProxy in
ScrollView(.vertical) {
VStack(spacing: 20) {
ForEach(items, id: \.self) { item in
Text("Item #\(item)")
.id(item)
.frame(height: 100)
.frame(width: 200)
.background(Color.green)
.onTapGesture {
withAnimation {
scrollProxy.scrollTo(item, anchor: .center)
}
}
.contentShape(Rectangle())
}
}
.padding(.horizontal, 20) /// <<< This padding causes the bug
.frame(width: geometryProxy.size.width)
}
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}