SwiftUI: различное поведение выравнивания контейнеров в GeometryReader
А
Text
элемент внутри
ZStack(alignment: .bottom)
отображается в нижней части контейнера (как и ожидалось). а если так же
ZStack
находится внутри
GeometryReader
, выравнивание больше не ведет себя так же.
Этот код:
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)
}
производит этот результат:
Если бы я хотел, чтобы "внутренняя география" тоже располагалась внизу, мне пришлось бы добавить
alignment: .bottom
внутри его родительского модификатора ZStack .frame(...).
Каковы предпосылки такого поведения? Почему я могу использовать
ZStack(alignment: ...)
в одном случае, но придется использовать
ZStack {...}.frame(alignment: ...)
в другом для достижения того же результата?
2 ответа
Это может показаться странным, но текст «Inside geo» в файле правильно выровнен по нижней части — проблема в том, что ваш текст не выровнен по нижней части файла .
Стеки занимают минимально необходимое пространство, в то время как имеет противоположное поведение. Таким образом, элемент выровнен по нижнему краю верхнего уровня, но занимает весь экран, а внутренний уровень располагается по центру внутри верхнего уровня.
GeometryReader
.
Попробуйте поставить
.background(someColor)
на каждом представлении, и вы увидите, где они расположены.
Если вы хотите, чтобы «Внутренняя гео» находилась внизу экрана, вам нужно указать
ZStack
чтобы оказаться внизу с
alignment
параметр - вот так:
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, alignment: .bottom) // Here you add the alignment parameter
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
После экспериментов я теперь знаю, что вызывает такое поведение, но сначала это казалось неожиданным.
При установке максимального размера .frame ZStack на .infinity (чтобы растянуть его), его «внутренний размер»/ содержимое по-прежнему остается «сжатым», а не растянутым. Это означает, что содержимое контейнера не всегда обязательно использует все пространство, которое могло бы быть.
Возьмите этот пример:
ZStack(alignment: .bottom) {
Color.red
.frame(width: 50, height: 50)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.blue)
Это приводит к совершенно другому размещению красного прямоугольника, чем при добавлении второго представления, которое раздвигает внутренние границы контейнера .
ZStack(alignment: .bottom) {
Color.red
.frame(width: 50, height: 50)
Color.clear
.frame(maxHeight: .infinity)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.blue)
Рамка чистого цвета теперь раздвигает границы своих родителей, поскольку ее высота пытается увеличиться настолько, насколько это возможно. GeometryReader имеет ту же природу, так как он всегда пытается заполнить своего родителя.
Теперь красная коробка больше не обнимается и имеет все пространство (вызванное чистым цветом) для свободного перемещения (вниз).
Вот два результата:
Заключение
Параметр