I had a layout that essentially looked like this:
ZStack(alignment: .bottom) {
GeometryReader { geometry in
ZStack {
Text("Centered")
}
.frame(width: geometry.size.width, height: geometry.size.height, alignment: .center)
.background(Color.red)
}
Group {
GeometryReader { geometry in // This GeometryReader is causing issues.
VStack {
Text("I want this at the bottom")
}
.frame(width: geometry.size.width, height: nil, alignment: .topLeading)
}
}
}
When this is rendered, both Text elements are rendered in the center of the screen. The second text element's container takes up the entire width of the screen, which is intended. If I remove the problematic GeometryReader, then the text is properly rendered at the bottom of the screen, but obviously the frame is not set to the entire width of the screen. Why is this happening?
By default SwiftUI containers tight to content, but GeometryReader
consumes maximum of available space. So if to remove second GeometryReader
the VStack
just wraps internal Text
.
If it is still needed to keep second GeometryReader
(to read width
) and put text to the bottom, the simplest approach would be to add Spacer
as below
Group {
GeometryReader { geometry in
VStack {
Spacer()
Text("I want this at the bottom")
}
.frame(width: geometry.size.width, height: nil, alignment: .topLeading)
}
}
Alternate approach of how to stick view at bottom you can find in my answer in this post Position view bottom without using a spacer
How about this?
struct ContentView: View {
var body: some View {
ZStack(alignment: .bottom) {
GeometryReader {geometry in
Text("Centered")
.frame(width: geometry.size.width, height: geometry.size.height)
.background(Color.red)
}
WidthReader {w in
Text("I want this at the bottom").frame(width: w)
}
}
}
}
struct WidthReader<Content: View>: View {
let widthContent: (CGFloat) -> Content
@State private var width: CGFloat = 0
@State private var height: CGFloat = 0
var body: some View {
GeometryReader {g in
widthContent(width).background(
GeometryReader {g1 in
Spacer().onAppear {height = g1.size.height}.onChange(of: g1.size.height, perform: {height = $0})
}
).onAppear {width = g.size.width}.onChange(of: g.size.width, perform: {width = $0})
}.frame(height: height)
}
}
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