🔦

4 Ways to Get View Size in SwiftUI: From GeometryReader to onGeometryChange

(Updated on )

TL;DR: In the early days of SwiftUI, GeometryReader was the only option for measuring view dimensions, but it often caused layout side effects due to its greedy nature. With the evolution of SwiftUI (specifically iOS 16, 17, and 18), we now have superior alternatives like onGeometryChange and visualEffect that offer better performance and cleaner architecture.

Dynamically obtaining a view’s size is a common requirement in SwiftUI. This article explores the 4 mainstream methods available as of 2025, helping you choose the best approach for your specific scenario.

1. The Universal Solution: GeometryReader

GeometryReader is the most compatible method, available in all SwiftUI versions. To prevent it from expanding greedily and ruining your layout, the best practice is to attach it as a background or overlay to the target view.

Code Example

Swift
blueRectangle
  .background(
    GeometryReader { proxy in
      Color.clear // Create a transparent view matching the parent's size
        .task(id: proxy.size) {
          size = proxy.size // Capture the size and monitor changes
        }
    }
  )

Characteristics:

  • Pros: Highest compatibility (works on all iOS versions).
  • Cons: Verbose syntax. If used directly (wrapping the view), it forces the view to expand to fill the available space, which often alters the intended layout.

Introduced in iOS 16 and enhanced in iOS 18, this is currently the most recommended way to retrieve view size. It is designed purely for monitoring geometry and does not affect the layout structure like GeometryReader.

Code Example

Swift
struct SizeDemo: View {
    @State var size: CGSize?
    var body: some View {
        Rectangle()
            // iOS 16+ Basic Usage
            .onGeometryChange(for: CGSize.self) { proxy in
                proxy.size
            } action: { newValue in
                size = newValue
            }
    }
}

iOS 18+ Enhancements

iOS 18 added support for accessing the previous value, which is incredibly useful for handling animations or transition logic:

Swift
.onGeometryChange(for: CGSize.self) { proxy in
    proxy.size
} action: { old, new in
    print("Size changed from \(old) to \(new)")
}

3. For Visual Effects Only: visualEffect

If your goal is to adjust visual effects (such as offset, scale, or blur) based on size, without altering the layout flow, visualEffect (introduced in iOS 17) is the most performant choice. It avoids the cycle of updating @State to trigger a re-render.

Code Example

Swift
struct EffectDemo: View {
    var body: some View {
        Rectangle()
            .foregroundStyle(.red)
            .visualEffect { content, proxy in
                // Use proxy directly to read size; no State binding needed
                content.offset(y: proxy.size.height / 3)
            }
    }
}

Effect

visualeffect-swiftui-demo

4. Container-Relative Layout: containerRelativeFrame

containerRelativeFrame (iOS 17+) is a powerful tool for “grid-like” or “split-screen” layouts. Instead of asking for a specific point value, you declare “what fraction of the container width this view should occupy.”

Code Example

The following code sets a rectangle to be 1/2 the width and 1/4 the height of its nearest container (e.g., Window or ScrollView):

Swift
struct TransformsDemo: View {
    var body: some View {
        Rectangle()
            .containerRelativeFrame([.horizontal, .vertical]) { length, axis in
                if axis == .vertical {
                    return length / 4
                } else {
                    return length / 2
                }
            }
    }
}

Application

It automatically looks up the view hierarchy to find the nearest specific container (like NavigationStack or ScrollView).

containerRelativeFrame-in-navigationStack

Implementing a “three cards per screen” layout in a ScrollView becomes trivial:

Swift
Rectangle()
    .containerRelativeFrame(.horizontal, count: 3, span: 1, spacing: 10)

containerRelativeFrame-scrollView

Summary: Which One to Choose?

MethodMin OSUse CaseRecommendation
onGeometryChangeiOS 16+Top Pick. When you need the numeric size value to update State.⭐⭐⭐⭐⭐
visualEffectiOS 17+For adjusting visual effects (offset, scale) only. No layout re-calculation triggered.⭐⭐⭐⭐
containerRelativeFrameiOS 17+When layout relies on proportional sizing relative to a parent (Screen/ScrollView).⭐⭐⭐⭐
GeometryReaderiOS 13+Legacy projects, or when you specifically need CoordinateSpace conversions.⭐⭐

Further Reading

Related Tips

Subscribe to Fatbobman

Weekly Swift & SwiftUI highlights. Join developers.

Subscribe Now