A Text
element inside a ZStack(alignment: .bottom)
is displayed at the bottom of the container (as expected). Tho, if the same ZStack
is inside a GeometryReader
, the alignment does not behave the same anymore.
This code:
var body: some View {
ZStack(alignment: .bottom) {
VStack {
Text("Outside geo")
}
GeometryReader { geo in
ZStack(alignment: .bottom) {
VStack {
Text("Inside geo")
}
}.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}.frame(maxWidth: .infinity, maxHeight: .infinity)
}
produces this result:
If I'd want the "inside geo" to be placed at the bottom too, I'd have to add alignment: .bottom
inside its parent ZStack .frame(...) modifier.
What's the background for this behavior? Why can I use ZStack(alignment: ...)
in one case, but have to use ZStack {...}.frame(alignment: ...)
in the other to achieve the same result?
After experimenting, I now know what causes this behavior, still it felt kinda unexpected first.
When setting the .frame max-size of the ZStack to .infinity (to stretch it out), its "inner size" / content still stays "hugged", rather than stretched out too. Means, the content of a container does not always necessarily use all the space it could.
Take this example:
This produces a whole different placement of the red box than when adding a second view, that pushes the inner bounds of the container.
The frame of the clear color now pushes its parents bounds, since its height tries to scale up as much as it can. A GeometryReader has the same nature, since it always tries to fill its parent.
Now the red box is not hugged anymore and has all the space (caused by the clear color) to move around freely (to the bottom).
Here are the two results:
Conclusio
The
alignment
parameter of.frame
decides where the hugged "inner frame" of a container is placed inside the full-frame of the container. Thealignment
parameter of a Container decides, where its content is placed inside its "inner frame" (which can be hugged).