Is it possible to read and write layout before render with SwiftUI?

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?

If you want to track the scroll position of an item within a scrollview and scroll back to that item at an given time you could use the scrollPosition API. The binding would automatticaly update the position of the prorpery as the user scrolls.

You can then query the currently scrolled id by using the viewID(type:)

When configuring a scroll position, SwiftUI will attempt to keep that position stable.

  • For an edge, that means keeping a top aligned scroll view scrolled to the top if the content size changes.
  • For a point, SwiftUI won’t attempt to keep that exact offset scrolled when the content size changes nor will it update to a new offset when that changes.

For view identity positions, SwiftUI will attempt to keep the view with the identity specified in the provided binding visible when events occur that might cause it to be scrolled out of view by the system. For example:

  • The data backing the content of a scroll view is re-ordered.
  • The size of the scroll view changes, like when a window is resized on macOS or during a rotation on iOS.
  • The scroll view initially lays out it content defaulting to the top most view, but the binding has a different view’s identity.

If you also want to read the scroll view geomery changes and perform an action whenever the scroll geometry changes use onScrollGeometryChange(for:of:action:)

Is it possible to read and write layout before render with SwiftUI?
 
 
Q