GeometryReader
A GeometryReader is primarily used to measure geometry. It gives us access to the proposed size through a geometry proxy, and the proxy also exposes related values such as the safe area insets and frame information.
The caveat is that a geometry reader always accepts the proposed size. Because of that, it is easy to change layout accidentally while trying to measure something. In practice, we often use geometry readers in overlays or backgrounds so they can measure a view without influencing its size.
Reading the Proposed Size
The core behavior is simple: the geometry reader accepts the proposed size, and reports that size to its closure through the proxy. In other words, proxy.size tells us what size the geometry reader itself ended up with. By default, the geometry reader places its contents at the top-leading corner.
GeometryReader { proxy in Text( "\(proxy.size.width) x \(proxy.size.height)" ) .font(.caption) .foregroundStyle(.white) .padding(6) .background(.blue) .fixedSize()}.border(.blue).padding()
Measuring a View
When we want to measure an existing view, the most useful pattern is to put the geometry reader in an overlay or background. The secondary view of an overlay gets proposed the size of the primary view, so the geometry reader can read that size without changing the layout. This is also the pattern we use on the debugging page.
Text("Measure me without changing layout.") .padding() .background { Rectangle() .fill(.orange) .opacity(0.2) } .overlay { GeometryReader { proxy in Text( "\(proxy.size.width) x \(proxy.size.height)" ) .font(.caption) .foregroundStyle(.white) .padding(6) .background(.blue) .fixedSize() .padding() } }
We can also see this behavior in the layout tree. The geometry reader unconditionally accepts the proposal, and then places its child at the top-leading corner within that region.
When It Causes Trouble
Many problems with geometry readers come from putting them directly around a view we wanted to measure. Because the geometry reader always becomes the proposed size, it can suddenly absorb flexible space inside containers such as HStack and VStack.
HStack(spacing: 12) { Text("Fixed") .padding(10) .frame(width: 70, height: 80) GeometryReader { proxy in Text( "reader: \(proxy.size.width) x \(proxy.size.height)" ) .font(.caption) .foregroundStyle(.white) .padding(6) .background(.blue) .fixedSize() } .border(.mint) Text("Fixed") .padding(10) .frame(width: 70, height: 80)}.padding(12)
There are two common ways to avoid this. We can either put the geometry reader in an overlay or background, or we can wrap something that is already completely flexible, such as a scroll view or another view that would have accepted the proposed size anyway.
Geometry Proxy
The proxy also provides access to safe area information. We cover that in more detail in the Geometry Reader section of the safe area page, because that interaction has its own set of rules.
A geometry proxy can also read frames in different coordinate spaces and resolve anchors. These features become useful in more advanced layout techniques, especially when we need to communicate geometry up the view tree or convert measurements between local, global, and named spaces. We'll come back to those patterns elsewhere rather than adding them here.
The proxy describes the geometry reader itself, not some abstract descendant. If we want to know how large a specific view became after layout, the measurement usually has to happen exactly where that view is rendered.