Reading time: 1 min

This quick recipe shows how to measure a SwiftUI View, i.e get its size at runtime. This is useful when your layout depends on a particular view's dimensions.

So the trick is to embed a GeometryReader in the view's background or overlay. The resulting GeometryProxy's size will the that of the view itself:

myView
  .background(GeometryReader { geometry in
    Color.clear // stretches as much as it can and is invisible
  })

If you wish to store the size in a State var, the preferred way is to use view preferences:

struct SizePreferenceKey: PreferenceKey {
  static var defaultValue: CGSize = .zero

  static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
    value = nextValue()
  }
}

struct MeasureSizeModifier: ViewModifier {
  func body(content: Content) -> some View {
    content.background(GeometryReader { geometry in
      Color.clear.preference(key: SizePreferenceKey.self, 
                             value: geometry.size)
    })
  }
}

extension View {
  func measureSize(perform action: @escaping (CGSize) -> Void) -> some View {
    self.modifier(MeasureSizeModifier())
      .onPreferenceChange(SizePreferenceKey.self, perform: action)
  }
}

Then, you can use it like this:

@State private var viewSize = CGSize.zero

var body: some View {
  myView.measureSize {
    viewSize = $0
  }
}

Next Post Previous Post