I am learning SwiftUI. And I come across to "GeometryReader". And I want to know why and when to use it?
Overview. CoordinateSpace allows a set of X, Y coordinates to have context on if they are relative to the frame's parent, or absolute to the device screen. It is also possible to define a custom coordinate space on a view with coordinateSpace(name:) .
All views have a natural position inside your hierarchy, but the offset() modifier lets you move them relative to that natural position. This is particularly useful inside ZStack , where it lets you control how views should overlap.
Since I posted the answer, I have also written an article on how GeometryReader works. Check it out for a more detailed explanation: https://swiftui-lab.com/geometryreader-to-the-rescue/
GeometryReader is a view that gives you access to the size and position of it's parent. For example:
struct MyView: View {
var body: some View {
GeometryReader { geometry in
// Here goes your view content,
// and you can use the geometry variable
// which contains geometry.size of the parent
// You also have function to get the bounds
// of the parent: geometry.frame(in: .global)
}
}
}
I usually combine it with .background() to obtain some other view's bounds. For example, The Text view is hard to predict how large it would be in advance. When I need that information, I use this trick:
First I have defined a view called GeometryGetter:
struct GeometryGetter: View {
@Binding var rect: CGRect
var body: some View {
return GeometryReader { geometry in
self.makeView(geometry: geometry)
}
}
func makeView(geometry: GeometryProxy) -> some View {
DispatchQueue.main.async {
self.rect = geometry.frame(in: .global)
}
return Rectangle().fill(Color.clear)
}
}
Then, to get the bounds of a Text view (or any other view):
struct MyView: View {
@State private var rect: CGRect = CGRect()
var body: some View {
Text("some text").background(GeometryGetter($rect))
// You can then use rect in other places of your view:
Rectangle().frame(width: 100, height: rect.height)
}
}
For some use cases, I posted some answers to other questions that use GeometryReader. Check them out:
Move textfields to avoid being hidden by the keyboard: https://stackoverflow.com/a/56721268/7786555
How to make view the size of another view in SwiftUI: https://stackoverflow.com/a/56661706/7786555
Note
In GeometryGetter, I added a DispatchQueue.main.async {} to set the rect. In some cases it could lead to runtime warning otherwise: Modifying state during view update.
Reader
in SwiftUI?In addition to the kontiki's answer, Reader
s are container views that define their content as a function. So they can have some access and abilities about their parent
. They are generic structs if you look more closely and there is 2 readers available now in SwiftUI 2.0:
Note that it's just a convention, they're not conforming special protocol more of the View
protocl.
struct GeometryReader<Content: View> : View
This is A container view that defines its content as a function of its own size and coordinate space. So you can detect frame and position changes and the current state of any view within a GeometryReader
. One of the popular usage of this reader that when you need separate views in separate stacks have the same (or relative) sizes.
struct ScrollViewReader<Content: View> : View
This is view whose child is defined as a function of a ScrollViewProxy
targeting the scrollable views within the child. So you can have some access to the scrollview like scrolling to a specific item in a list or similar stuff.
To minimalizing the duplication, I didn't post examples, you can check the link for more information if you want
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With