Макет SwiftUI внутри VStack с использованием ViewModifiers

У меня простой вид с двумя текстами. Его body выглядит так:

VStack {
    Text("One")
    Text("Two")
    Text("Three")
}

это создает вид вроде:

Существующий макет

Но я бы хотел, чтобы при использовании только модификаторов для Text представлений (т.е. без HStack с Spacers) получился такой макет:

Желаемый макет

Возможно ли это сейчас? Я надеялся каким-то образом сделать Texts полной шириной, а затем просто использовать выравнивание текста, но я еще не понял этого.


person KerrM    schedule 20.03.2020    source источник


Ответы (3)


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

Демо в предварительном просмотре (синяя рамка - это просто выделение в коде)

демонстрация

    VStack {
        Text("One")
            .frame(maxWidth: .infinity, alignment: .leading)
        Text("Two")
        Text("Three")
            .frame(maxWidth: .infinity, alignment: .trailing)
    }
person Asperi    schedule 20.03.2020
comment
Большое спасибо! Можете ли вы предвидеть какие-либо недостатки этого использования? т.е. странно ли использовать выравнивание фрейма для выравнивания текста? - person KerrM; 20.03.2020
comment
@KerrM, нет, на самом деле он выравнивается не по тексту (т.е. строке), а целиком внутри предоставленного фрейма. Поэтому, если вы вставляете очень длинный текст, он заполняется и переносится обычным образом. Более того, поскольку нет жесткого кода, изменение ориентации или макета будет выполняться автоматически. - person Asperi; 20.03.2020

Да, это возможно. Вы можете определить такой модификатор, как:

extension View {
    func horizontalAlignment(_ alignment: HorizontalAlignment) -> some View {
        Group {
            if alignment == .leading {
                HStack {
                    self
                    Spacer()
                }
            } else if alignment == .trailing {
                HStack {
                    Spacer()
                    self
                }
            } else {
                self
            }
        }
    }
}

И используйте это так:

VStack {
    Text("One")
        .horizontalAlignment(.leading)
    Text("Two")
        .horizontalAlignment(.center)
    Text("Three")
        .horizontalAlignment(.trailing)
}

Конечно, возможны несколько подходов.

person cbjeukendrup    schedule 20.03.2020

Один из подходов - просто установить фрейм:

struct ContentView: View {
    var body: some View {
        VStack {
            Text("One")
                .frame(minWidth: 0,
                       maxWidth: .infinity,
                       alignment: .leading)
            Text("Two")
                .frame(minWidth: 0,
                       maxWidth: .infinity,
                       alignment: .center)
            Text("Three")
                .frame(minWidth: 0,
                       maxWidth: .infinity,
                       alignment: .trailing)

        }
    }
}
person atomoil    schedule 20.03.2020