Skip to content

Tracking Geometry Changes (SwiftUI)

A SwiftUI guide for coding agents. Also covers ongeometrychange modifier, measure view size, geometryreader replacement, scroll offset ios 16, coordinate space frame.

The onGeometryChange view modifier observes a view's size or frame without a GeometryReader wrapper, so it cannot break your layout. It back-deploys to iOS 16, macOS 13, tvOS 16, watchOS 9, and visionOS 1, which makes it the compatible way to track geometry.

The Three Parameters

Provide an equatable result type, a transformation that reduces the GeometryProxy to that type, and an action that receives the value. Geometry changes constantly during scrolling, so SwiftUI runs the action only when the transformed value changes; keep the value small.

@State private var size: CGSize = .zero

ScrollView {
  Color.red.onGeometryChange(for: CGSize.self) { geometry in
    geometry.size
  } action: { newValue in
    size = newValue
  }
}

Backward-Compatible Scroll Offset

A zero-height marker view plus a named coordinate space tracks the scroll offset on iOS 16, where the iOS 18 scroll geometry APIs do not exist.

@State private var offset: CGFloat = 0

ScrollView {
  Color.clear
    .frame(height: 0)
    .onGeometryChange(for: CGFloat.self) { geometry in
      geometry.frame(in: .named("scrollView")).minY
    } action: { newValue in
      offset = newValue
    }

  // scroll content
}
.coordinateSpace(.named("scrollView"))

GeometryProxy.frame(in:) resolves the frame in any coordinate space you have declared with coordinateSpace.

The Old-and-New Overload

An action closure taking (old, new) values exists too, but only on the iOS 18 generation of platforms; it does not back-deploy. Stick to the single-value action for compatible code.

} action: { old, new in
  offset = min(old, new)
}

Use this guidance in your coding agent

Install the Better Design MCP once. Your agent then loads this page with one call.

get-swiftui-guide({ topic: "swiftui-tracking-geometry-changes" })
claude mcp add --scope user better-design --transport http https://better-design.com/api/mcp --header "Authorization: Bearer <YOUR_API_KEY>"
Browse related design systems