GeometryReader is a great tool for creating custom layouts with SwiftUI. It enables you to pass geometry information to child views. However, when creating complex layouts you might want to pass geometry information to the parent or sibling views as well. Luckily you can use .overlay()
to achieve exactly this.
The
.overlay()
or.background()
ViewModifier allows you to share a View’s geometry up the view hierarchy.
Demo Use Case
Let’s have a look at the following use case as an example on why this can be really powerful.
We have a simple View consisting of an Image and a Text. The Text should take all the space it needs and the Image the remaining space. Because the Text can contain a very long string (and to support larger TextSizes), we need to wrap the entire View inside a ScrollView. However the ScrollView will calculate it’s intrinsic content size according to it’s containing views. This means that the Image will take all the space it needs, resulting in unwanted scrolling even for short strings. What we really want is the Image to shrink with increasing string length until a certain threshold height (say 200p).
This means that the Image’s height should depend on the height of the Text and the extrinsic content size of the ScrollView:
Thanks to the combination of GeometryReader and .overlay()
we can achieve exactly that. .overlay()
adds an additional view in front of another view with exactly the same size (whereas .background()
adds an additional view behind another view). We can then add a GeometryReader inside the overlay View with a transparent View inside it. By implementing .onAppear() on the transparent View we can store the GeometryProxy information inside an @State property which is accessible by all views.