Max
Max

Reputation: 15985

Alignment changes after adding a GeometryReader

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?

Upvotes: 23

Views: 11982

Answers (3)

Levan Karanadze
Levan Karanadze

Reputation: 471

The easiest way is to add the .fixedSize() modifier to your Stack.

Upvotes: -1

Asperi
Asperi

Reputation: 258345

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

enter image description here

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

Upvotes: 10

蘇哲聖
蘇哲聖

Reputation: 795

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)
    }
}

Upvotes: 1

Related Questions