In a SwiftUI app, you can use GeometryReader
to dynamically get the view size.
This article explains how to do it.
Output the View Size into the Console
Following the code, get the view size using GeometryReader
and print it into the console.
struct ContentView: View {
var body: some View {
Text("Hello, world!")
.padding()
.background() {
GeometryReader { geometry in
Path { path in
print("Text frame size = \(geometry.size)")
}
}
}
}
}
This code prints the size of Text
into the console as below.
Text frame size = (126.66666666666666, 52.33333333333333)
Place the GeometoryReader in the background
In SwiftUI, GeometryReader
enables the view to get its size. So, you need to place the GeometryReader
in the background of the view which you want to investigate the size by using the background
modifier. SwiftUI resizes the background view to the same as the foreground view.
The geometry
is a GeometryProxy
structure. The GeometryProxy.size
property has its view size.
You can also use Overlay
You can also use the overlay
modifier instead of the background
modifier to get the size with GeometryReader
. You can choose one of them depending on the situation.
Example: Display into the Label
Let’s implement the code which displays the size into the Text
instead of the console.
struct ContentView: View {
@State private var labelSize: CGSize = CGSize()
var body: some View {
VStack {
Text("Hello, world!")
.padding()
.background() {
GeometryReader { geometry in
Path { path in
let size = geometry.size
DispatchQueue.main.async {
if self.labelSize != size {
self.labelSize = size
}
}
}
}
}
Text("Label Size : \(String(format: "%.0f x %.0f", labelSize.width, labelSize.height))")
}
}
}
This code creates two labels. The lower ones display the size of the upper ones.
You can’t use the size while building views
This code assigns the getting size into the labelSize
property, and the Text
view displays the value of this property. This property has a @State
attribute, so SwiftUI manages the labelSize
property and contents of the Text
view.
It’s crucial to be mindful of when you’re using GeometryReader
to get the size, as the ContentView
is still being built. If the labelSize
property value changes, the ContentView
needs to be rebuilt. However, it causes an error that changes the value while building. As a result, the Text
view can’t display it.
If you run the code without DispatchQueue.main.async
, the live preview of Xcode displays the value. Still, the iOS Simulator and the actual device can’t show the valid value.
Xcode also reports the error as below.
Modifying state during view update, this will cause undefined behavior.
This sample code employs the DispatchQueue.main.async
method, which postpones property assignment until the view building is complete.