I’m trying to keep a specific row visually stable while the data backing a ScrollView changes.
Goal 1. Before updating model.items, capture the top row’s offset relative to the scroll view. 2. Mutate the observable state so SwiftUI recomputes layout — but don’t draw yet. 3. Read the new layout, compute the delta, and adjust the scroll position so the previously visible row stays put. 4. Only then draw the new frame.
Reduced example
@Observable
final class SomeModel {
var items: [SomeItem] = [/* ... */]
}
struct MyBox: View {
@Environment(SomeModel.self) private var model
var body: some View {
ScrollView {
VStack {
ForEach(model.items, id: \.id) { item in
Color.red.frame(height: randomStableHeight(for: item.id))
}
}
}
}
}
// Elsewhere:
let oldRow = recordOldRow() // capture the row to stabilize
model.items = generateNewItems() // mutate model (invalidates layout)
let newPos = capturePreviousRowNewPosition(oldRow) // read new layout?
restoreScrollPosition() // adjust so oldRow stays visually fixed
// draw now
Is that pipeline achievable in SwiftUI? If not, what’s the supported way to keep a row visually stable while the list updates?