SwiftUI: невозможно выровнять изображение по верху ZStack - PullRequest
1 голос
/ 24 января 2020

Я не могу понять, как выровнять Image представление поверх ZStack, по умолчанию представления в SwiftUI размещаются в центре их родительского элемента, и затем мы используем стеки для их выравнивания. У меня есть следующее кусок кода:

struct ContentView: View {
    var body: some View {
        ZStack {
           Image("bgImage")
           Text("Hello, World!")
        }
    .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.red) //this is for debugging purposes, to show the area of the ZStack
    }
}

как я могу расположить изображение вверху?

enter image description here

Ответы [ 2 ]

2 голосов
/ 24 января 2020

Чтобы заставить ZStack выравнивать вещи определенным образом внутри него, настройте его с параметром alignment:

ZStack(alignment: .top) {
    Color.clear
    Image(...)
    Text("Hello, World!")
}

(Color.clear расширяется, чтобы заполнить все доступное пространство, поэтому это заставляет ваш ZStack быть таким же большим, как окружающий вид, без добавления .frame().)

Это, конечно, выровняет все вверху, что может быть не тем, что вы хотите. Вы можете исправить это, сделав вложение ваших ZStacks так, чтобы выровнять их так:

ZStack{
    ZStack(alignment: .top) {
        Color.clear
        Image(...)        // This will be at the top
    }
    Text("Hello, World!") // This will be centered
}

Тем не менее, я бы, вероятно, использовал .background для этого примера.

ZStack {
    Color.clear
    Text("Hello, World!")
}
.background(Image(...), alignment: .top)

И если у вас есть только один вид, вы можете избавиться от ZStack и использовать вместо него рамку:

Text("Hello, World!")
    .frame(maxHeight: .infinity)
    .background(Image(uiImage:#imageLiteral(resourceName: "image.jpg")), 
                alignment: .top)

Имейте в виду, что в этом случае изображение будет рисоваться вне рамок. Во многих случаях это нормально (и совершенно законно), но иногда это может иметь значение (например, если вы кладете это в стек). Вы можете добавить .border(Color.green) в конец, чтобы увидеть, как это работает.


Этот пример действительно попадает в суть макета SwiftUI, так что стоит понять, что происходит. Это не обходной путь или уловка, поэтому вы должны добраться до места, где это выглядит очень нормально.

Представление содержимого верхнего уровня (которое содержит ZStack) предлагает все пространство для ZStack. , ZStack всегда точно соответствует размеру его содержимого, , поэтому сначала ZStack должен расположить свои дочерние элементы. Он размещает их в соответствии со своим выравниванием, а затем подбирает их размеры точно так, чтобы они подходили вокруг них. Таким образом, с выравниванием по верху (но без Color.clear) изображение находится в верхней части ZStack. Размер ZStack точно такой же, как и у изображения.

Представление содержимого верхнего уровня помещает ZStack в его центр.

То, как ZStack размещает свои дочерние элементы, аналогично тому, как просмотр содержимого сделал. Он предлагает все пространство, которое ему было предложено, и затем дети-дети выбирают свои размеры. Представления всегда определяют свои собственные размеры. Изображение и текст являются представлениями фиксированного размера, поэтому они просто соответствуют размеру их содержимого. Но цвет - это представление гибкого размера. Он принимает все пространство, предлагаемое ZStack (то же самое пространство, которое предлагалось представлением содержимого верхнего уровня), и возвращает его в качестве своего размера. Поскольку ZStack должен точно содержать своих дочерних элементов, ZStack теперь имеет размер представления содержимого верхнего уровня, и все ведет себя так, как вы ожидаете, выравнивая верхнюю часть экрана.

Давайте сравним с использованием .frame() как вы изначально это делали:

ZStack {
   Image("bgImage")
   Text("Hello, World!")
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.red) //this is for debugging purposes, to show the area of the ZStack

Во-первых, я хочу сосредоточиться на вашем комментарии, потому что это не правильно. Это не область ZStack. ZStack - это размер его содержимого (изображение и текст). Вы помещаете фон в раму, а рама становится больше.

Основная путаница в том, что они думают, что .frame(...) меняет размер вида, к которому он прикреплен. Это совсем не правильно. Как и раньше, a ZStack всегда имеет размер своего содержимого. .frame() создает совершенно новое представление запрошенного размера. Затем он размещает упакованный вид внутри себя в соответствии с выравниванием кадра. Таким образом, в этом примере это работает так:

Верхний уровень - Фон - Рамка - ZStack - {Текст изображения}

Представление верхнего уровня предлагает все свое пространство для фона. Фоны - это размер того, что они содержат, поэтому он предлагает все это пространство для фрейма. Фрейм является гибким в обоих направлениях (благодаря полям max), поэтому он игнорирует размер дочернего элемента и выбирает размер, который был ему предложен.

Фрейм затем предлагает все это пространство для ZStack. , ZStack размечает свои дочерние элементы и возвращает его размер как раз тот размер, который их содержит.

Затем Frame помещает ZStack в соответствии с выравниванием Frame (.center, поскольку это значение по умолчанию). Если бы вы установили выравнивание фрейма на .top, тогда ZStack был бы помещен вверху фрейма (но текст был бы центрирован в ZStack не во фрейме).

Затем он сообщает Фону, что он равен размеру представления верхнего уровня (поскольку он гибкий).

Фон затем заявляет тот же размер к представлению содержимого верхнего уровня.

И, наконец, представление содержимого верхнего уровня помещает фон в его центр.

0 голосов
/ 25 января 2020

Таким образом, одна вещь, работающая против вас, это модификатор infinity maxHeight, предполагая, что вам не нужно пространство между изображением и нижней частью вида.

.edgesIgnoringSafeArea(.all)

Возможно, вам просто нужно сообщить свой ZStack игнорировать вставки безопасной области.

struct ContactsView: View {
  var body: some View {

    ZStack {
      Image("bgImage")
      Text("Hello, World!")
    }.frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.red).edgesIgnoringSafeArea(.all)

  }
}

Если вам нужно пространство между дном и изображением, оберните ZStack в VStack и бросьте Spacer в нижней части VStack.

struct ContactsView: View {
  var body: some View {
    VStack {

      ZStack {
        Image(systemName: "bgImage")
        Text("Hello, World!")
      }.frame(maxWidth: .infinity, maxHeight: 300).background(Color.red)

      Spacer()

    }.edgesIgnoringSafeArea(.all)
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...