Правильный способ разметки SwiftUI (аналог Autolayout) - PullRequest
0 голосов
/ 08 июля 2020

Вопрос:

Я изо всех сил пытаюсь эффективно разметить представления с помощью SwiftUI. Я очень хорошо знаком с UIKit и Autolayout и всегда считал его интуитивно понятным.

Я знаю, что SwiftUI молодой и только начинается, поэтому, возможно, я ожидаю слишком многого, но возьму простой пример:

a HStack из Text() просмотров.

|--------------------------------|
| Text("static") Text("Dynamic") |  
|________________________________|

Когда у меня есть Dynami c контент, stati c Текстовые строки перепрыгивают через все место при изменении размера HStack, при изменении текста ("Dynami c") ...

Я много чего перепробовал, Spacers(), Dividers(), посмотрел подходы с использованием PreferenceKeys ( ссылка ), Alignment Guides ( ссылка )

Наиболее близким к ответу кажется руководство по выравниванию, но оно запутанное.

Какой канонический подход к воспроизведению способности Autolayout в основном привязывать виды к краю экрана и правильно размещать макеты, не прыгая по сторонам?

Я хотел бы привязать stati c текст «Широта» чтобы он не прыгал.

Есть и другие примеры, поэтому более общий ответ о том, как лучше к макету были бы признательны ...

С Autolayout я чувствовал, что выбрал то, что пошло. С SwiftUI это лотерея.

Пример, показывающий, как слово «Широта» перескакивает при изменении координат:

Проблема

Пример, код:

HStack {
    Text("Latitude:")
    Text(verbatim: "\(self.viewModelContext.lastRecordedLocation().coordinate.latitude)")
}

Я действительно борюсь, когда мои представления меняют контекст / динамический c. Все работает нормально для содержимого stati c, как показано во всех видеороликах WWD C.

Возможное решение:

Использование HStack, например:

HStack(alignment: .center, spacing: 20) {
    Text("Latitude:")
    Text(verbatim: "\(self.viewModelContext.lastRecordedLocation().coordinate.latitude)")
    Spacer()
}
.padding(90)

Результат хорошо закреплен, но я ненавижу магов c числа.

1 Ответ

2 голосов
/ 08 июля 2020

Как вы уже в некоторой степени обнаружили, первая часть состоит в том, что вам нужно решить, чего вы хотите. В этом случае вам, кажется, требуется выравнивание по левому краю (на основе вашего решения для заполнения). Так что это хорошо:

    HStack {
        Text("Latitude:")
        Text(verbatim: "\(randomNumber)")
        Spacer()
    }

Это сделает HStack такой же шириной, как и его содержащее представление, и sh текст слева.

Но, судя по вашим более поздним комментариям, вам кажется, не желать, чтобы он был крайним левым. Вы должны решить, что именно вы хотите в этом случае. Добавление .padding позволит вам переместить его слева (возможно, добавив только .leading), но, возможно, вы захотите сопоставить его с размером экрана.

Вот один из способов сделать это. Важно помнить базовый алгоритм c для HStack, который должен предоставить каждому свой минимум, а затем разделить оставшееся пространство между гибкими представлениями.

    HStack {
        HStack {
            Spacer()
            Text("Latitude:")
        }
        HStack {
            Text(verbatim: "\(randomNumber)")
            Spacer()
        }
    }

Внешний HStack имеет 2 дочерних элемента, все они гибкие до некоторого минимума, поэтому он предлагает каждому равное количество пространства (1/2 от общей ширины), если он может это вместить.

(Я изначально сделал это с двумя дополнительными прокладками, но я забыл, что у проставок, кажется, есть особая обработка, чтобы их пространство оставалось последним.)

Вопрос в том, что произойдет, если randomNumber будет слишком длинным? Как написано заверну. В качестве альтернативы вы можете добавить .fixedSize(), чтобы остановить его от переноса (и pu sh Latitude слева, чтобы он соответствовал). Или вы можете добавить .lineLimit(1), чтобы заставить его усечь. Выбор за вами.

Но важно добавить гибкие HStacks. Если каждый ребенок гибок, тогда все они получат одно и то же пространство.

Если вы хотите разделить вещи на трети или четверти, я считаю, что вам нужно добавить что-то другое, кроме спейсера. Например, это даст Latitude и номер 1/4 доступного пространства, а не 1/2 (обратите внимание на добавление Text("")):

    HStack {
        HStack {
            Text("")
            Spacer()
        }
        HStack {
            Spacer()
            Text("Latitude:")
        }
        HStack {
            Text(verbatim: "\(randomNumber)")//.lineLimit(1)
            Spacer()
        }
        HStack {
            Text("")
            Spacer()
        }
    }

В моем собственном коде я делаю это таких вещей, как

struct RowView: View {   
    // A centered column
    func Column<V: View>(@ViewBuilder content: () -> V) -> some View {
        HStack {
            Spacer()
            content()
            Spacer()
        }
    }

    var body: some View {
        HStack {
            Column { Text("Name") }
            Column { Text("Street") }
            Column { Text("City") }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...