LazyVStack inside ScrollView produces nested scroll regions on Android
Nobody has claimed this yet.
- Dominant language
- Swift
- Stars
- 3.2k
- Forks
- 106
- Avg merge
- 6d 13h
- Merged PRs (30d)
- 1
Description
LazyVStack nested inside a ScrollView works as expected on iOS (lazy rows feed into the parent scroller) but on Android produces two competing scroll regions: content above the LazyVStack scrolls independently from the LazyVStack itself. No compile-time or transpile-time warning is emitted; the divergence only surfaces at runtime during UX.
Repro:
import SwiftUI
struct ContentView: View {
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 16) {
Text("Header section").font(.headline)
ForEach(0..<5) { i in
Text("Header row \(i)")
}
LazyVStack(alignment: .leading, spacing: 8) {
Text("List section").font(.headline)
ForEach(0..<50) { i in
Text("List row \(i)")
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
.background(Color.gray.opacity(0.1))
}
}
}
.padding()
}
}
}
Expected (iOS behavior)
Single scroll region. The header rows scroll off the top of the screen as the user pulls the list rows into view. LazyVStack lazily materializes its rows but defers scrolling to the parent ScrollView.
Actual (Android behavior)
Two independent scroll regions. The header section stays in place while the LazyVStack scrolls within its own bounded region — and vice versa, scrolling outside the LazyVStack doesn't move the lazy content.
Diagnosis
It looks like LazyVStack is being translated to Compose's LazyColumn, which is itself a scroll container with its own viewport. This may be an anti-pattern in Android.
Suggested fix
When LazyVStack appears inside a ScrollView, translate it to a plain Column rather than LazyColumn, giving up laziness on Android (acceptable: it matches what one would write by hand to avoid the nesting issue) in exchange for correct scroll behavior matching iOS. Or alternatively, emit a transpile-time warning so the divergence isn't silent.
The current workaround in user code is to swap LazyVStack → VStack, which works but defeats the purpose of LazyVStack for users who genuinely want lazy loading on long lists.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the Android translation entry points for LazyVStack inside ScrollView and reproduce the SwiftUI example from the issue. Compare the generated LazyColumn and parent scroll behavior, then add or run a regression test for nested scrolling. Done means the header and list share one scroll region without a silent runtime divergence.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, swift
- Domain
- mobile-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100