GeometryReader in SwiftUI is a container view that provides access to its size and position within the parent view. Although you won’t always need to use it, it’s available when you’d like to know more about the views you’re working with. This is for you if you need to work more precisely, particularly with different screen sizes.
The Basics of GeometryReader
To see what information you can get with GeometryReader, take a look at the following:
struct ViewWithGeometryReader: View {
var body: some View {
GeometryReader { geometry in
Text("\(geometry.frame(in: .global).debugDescription)")
}
.padding(0)
.background(.green)
}
}
Here we have a struct with a friendly name of “ViewWithGeometryReader”. Call it whatever you like.
On line 3 we create the GeometryReader container view. This has a closure that provides a GeometryProxy called geometry in this case. This allows us to access properties that provide the container’s dimensions and coordinates.
In the container view we have a Text view that shows details of the global frame. This can be changed to .local if needed to show the details of the current frame with x and y starting at zero. In this instance, running on the simulator as an iPhone 15 pro we see at the top of the screen the text showing x, y, width, height. Note that when using .global, the y coordinate is not zero because it takes into consideration the insets.
To put this to use we can use the following in our ContentView:
var body: some View {
VStack(spacing: 0) {
HStack(spacing: 0) {
ViewWithGeometryReader()
ViewWithGeometryReader()
}
.padding(0)
ViewWithGeometryReader()
ViewWithGeometryReader()
}
.padding(0)
}
Here, we have a VStack with spacing and padding set to zero (by default, there is some padding and spacing added to views, so we are removing it for this example). We then have a HStack with the same padding and spacing set, which contains two ViewWithGeometryReader views, and then in the VStack which contains a repeat of the same two views.
Looking at this in the preview shows the following:
This contains the four views, two side by side at the top followed by two more below. The x coordinates for the left in the HStack and two in the VStack show 0.0 because they are at the left of the screen. The y coordinate shows 59.0 for the top two (remember it respects the insets in this example), followed by 312.0 and 565.0.
We then have the width and height for each view displayed.
Why is this useful?
Take this chart as an example. It uses the Charts framework for the outer ring, but the inside is a Text view. By placing the Chart and the Text in a ZStack container view, we can use the GeometryReader to get the width and height of the container and set its position as follows:
Text("\(Int(stepCount))")
.font(.system(size: min(geometry.size.width, geometry.size.height) * 0.2))
.bold()
.padding()
.foregroundColor(.black)
.accessibilityLabel("Steps taken today")
.accessibilityValue("\(Int(stepCount)) steps")
.frame(maxWidth: .infinity, maxHeight: .infinity)
.position(x: geometry.size.width / 2,
y: geometry.size.height / 2)
Note that we set the position to the geometry.size.width / 2 and the same for the height. This centres the Text view in the centre of the chart regardless of where it is on screen.
We can also use the geometry to decide the font size so that it scales when the frame used needs to be resized. Here is how this view might be seen when placed multiple times in a H and V stacks:
The top three views are smaller, and because of GeometryReader, we can position the Text view in the centre, as well as resize it. If you need information about the view, then GeometryReader is the way to go. If you have any questions, please ask in the comments.
Leave a Reply
You must be logged in to post a comment.