[Submitted as FB21961572]
When navigating from a tile in a scrolling LazyVGrid to a child view using .navigationTransition(.zoom) and then returning, the source tile can lag behind the rest of the grid if scrolling starts immediately after returning.
The lag becomes more pronounced as tile content gets more complex; in this simplified sample, it can seem subtle, but in production-style tiles (as used in both of my apps), it is clearly visible and noticeable.
This may be related to another issue I recently filed:
CONFIGURATION
- Platform: iOS Simulator and physical device
- Navigation APIs: matchedTransitionSource + navigationTransition(.zoom)
- Container: ScrollView + LazyVGrid
- Sample project: ZoomTransition (DisappearingTile).zip
REPRO STEPS
- Create a new iOS project and replace ContentView with the code below.
- Run the app in sim or physical device
- Tap any tile in the scrolling grid to navigate to the child view.
- Return to the grid (back button or edge swipe).
- Immediately scroll the grid.
- Watch the tile that was just opened.
EXPECTED
All tiles should move together as one coherent scrolling grid, with no per-item lag or desynchronization.
ACTUAL
The tile that was just opened appears to trail behind neighboring tiles for a short time during immediate scrolling after returning.
MINIMAL CODE SAMPLE
import SwiftUI
struct ContentView: View {
@Namespace private var namespace
private let tileCount = 40
private let columns = [GridItem(.adaptive(minimum: 110), spacing: 12)]
var body: some View {
NavigationStack {
ScrollView {
LazyVGrid(columns: columns, spacing: 12) {
ForEach(0..<tileCount, id: \.self) { index in
NavigationLink(value: index) {
RoundedRectangle(cornerRadius: 16)
.fill(color(for: index))
.frame(height: 110)
.overlay(alignment: .bottomLeading) {
Text("\(index + 1)")
.font(.headline)
.foregroundStyle(.white)
.padding(10)
}
.matchedTransitionSource(id: index, in: namespace)
}
.buttonStyle(.plain)
}
}
.padding(16)
}
.navigationTitle("Zoom Transition Grid")
.navigationSubtitle("Open tile, go back, then scroll immediately")
.navigationDestination(for: Int.self) { index in
Rectangle()
.fill(color(for: index))
.ignoresSafeArea()
.navigationTransition(.zoom(sourceID: index, in: namespace))
}
}
}
private func color(for index: Int) -> Color {
let hue = Double(index % 20) / 20.0
return Color(hue: hue, saturation: 0.8, brightness: 0.9)
}
}
SCREEN RECORDING