The problem
When I populate a LazyVStack
with items of varying heights, the ScrollView
around it does not behave as expected on macOS 13. This simplified example is still somewhat usable, but as you can see in the screen recording (I'm scrolling very slowly), the scroll position jumps around. In my production app this behavior gets much worse, making it sometimes impossible to scroll upwards again.
Code
struct ContentView: View {
var body: some View {
ScrollView {
LazyVStack {
ForEach(1...40, id: \.self) { value in
Item(value: value)
.id(value)
.padding()
}
}
.padding()
}
.frame(width: 300, height: 300)
}
}
struct Item: View {
let value: Int
let lorem = "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."
var body: some View {
if value < 20 {
Text("\(value) A long text: \(lorem)")
}
else {
Text("\(value) A short text")
}
}
}
iOS vs. macOS
I have found this post regarding the same issue on iOS. I also ran my code on iOS and while the scroll indicator changes its height (which would indicate a change in content size), the scrolling was smooth without jumps of the scroll position.
Question
Has anyone had the same issue and found a way to make this work? The example would easily work with a regular VStack
, but I need to use LazyVStack
for performance reasons and the ability to add a sticky header.