Hey, I've been having a problem with scroll views in combination with the .geometryGroup()
modifier.
I have filed a Feedback (FB17698293) but I also wanted to post this here in case someone maybe has a better workaround for the problem.
Problem
Whenever you conditionally insert a ScrollView
inside a VStack
that is modified with a .geometryGroup()
modifier, the scroll view content offset resets itself after the insertion animation is done, even if you started scrolling inside the scroll view during the animation and haven't let go of the screen. This happens consistently and is fully reproducible (see below), both using a simulator and a real device.
Unfortunately, this is a very annoying glitch that ruins a lot of cool UX components that rely on .geometryGroup()
.
The weird thing is that the glitch entirely disappears, if you add a simple, non-zero (but greater than 1) .padding()
modifier to the VStack (.padding().geometryGroup()
).
I have no idea why this fixes the glitch, but it does. However, adding a padding is not feasible in many situations, so this workaround is not ideal.
Steps to reproduce
- Launch the code below (using a simulator or a real device) and tap "Toggle Expansion" to insert the scroll view.
- As the view is animating in, drag the scroll content and hold it scrolled away from the top.
- Wait for the animation to complete. The scroll view will reset the content offset, even though the drag gesture is still active (i.e. you haven't lifted your finger to release the scroll view)
- On a real device, this sometimes even leads to an even worse visual artifact where the scroll view is rendered twice for a few frames; once with the correct offset, and once with the reset offset.
I wanted to include a link to a gif/video showing the glitch, but it tells me that imgur is not allowed on the forums.
Expected Behavior
I want the scroll view to respect the content offset, even if I started changing it mid-animation.
Xcode Version
I am using Xcode 16.4 (16F6) but this problem has been occurring since the .geometryGroup() modifier has been release. I was only now able to pinpoint this problem exactly, so I'm filing this feedback.
Code
The entire code that reproduces the problem:
import SwiftUI
struct ContentView: View {
@State private var isExpanded: Bool = false
var body: some View {
VStack {
if isExpanded {
ScrollView {
Text(loremIpsum)
}
}
Button("Toggle Expansion") {
isExpanded.toggle()
}
}
// .padding(10) // Adding a non-zero padding makes the glitch disappear
.frame(maxWidth: .infinity)
.geometryGroup()
.animation(.default, value: isExpanded)
}
}
#Preview {
ContentView().preferredColorScheme(.dark)
}
// MARK: - Mock Data
let loremIpsum = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt \
ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco \
laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla \
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt \
mollit anim id est laborum.
"""