UPDATE
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.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…