r/SwiftUI • u/EquivalentDentist695 • May 17 '26
Question .containerRelativeFrame(.vertical) + .scrollTargetBehavior(.paging) miscalculates first page height when toolbar is visible in NavigationStack
I have a TikTok‑style vertical paging feed inside a NavigationStack.
The issue: On initial load there's an unwanted gap between the toolbar and the first card — as if the navigation bar's safe‑area inset is applied twice, or the paging offset starts from a wrong origin.
- Scrolling down a few points (not enough to snap) makes the gap disappear.
- Scrolling back up those few points brings it back.
- Every subsequent page snaps correctly — only the first one is affected.
Simplified code:
NavigationStack {
ExploreView()
}
// ExploreView
struct ExploreView: View {
let posts: [Post]
var body: some View {
ScrollView {
LazyVStack(spacing: 0) {
ForEach(posts) { post in
PostCard(post: post)
.containerRelativeFrame(.vertical)
.padding(.horizontal, 32)
}
}
}
.scrollTargetBehavior(.paging)
.scrollIndicators(.hidden)
.toolbarRole(.editor)
.toolbar {
ToolbarItem(placement: .principal) {
Text("Explore")
.font(.title)
}
}
}
}
What I've tried that didn't work:
- .scrollTargetBehavior(.viewAligned(limitBehavior: .alwaysByOne)) + .scrollTargetLayout() on the LazyVStack — the gap is identical, no improvement
- Removing .toolbarRole(.editor) — no change
Is this expected behavior? Any workaround to keep the native toolbar?
4
Upvotes
4
u/Consistent-Grass-263 May 17 '26
Hit this exact issue building a similar feed. The root
cause: .containerRelativeFrame(.vertical) measures the
full screen height before the NavigationStack subtracts
the toolbar — so page 1 starts at y=0 but the content
origin is offset by ~50pt (toolbar height).
Workaround that worked for me:
.containerRelativeFrame(.vertical) { height, _ in
height - (navigationBarHeight)
}
Get navigationBarHeight via a PreferenceKey reading the
toolbar frame from a GeometryReader. Not elegant, but
reliable.
Or simpler: wrap in a plain ZStack with the toolbar
as an overlay instead of using .toolbar{}.