SwiftUI выравнивание по правому краю - PullRequest
0 голосов
/ 07 октября 2019

Я пытаюсь добиться выравнивания метки по правому краю. Вот пример:

Right-aligned example

Обратите внимание, что надписи слева выровнены по правому краю. Это кажется простым, но я не нашел способа сделать это в SwiftUI таким образом, чтобы он мог обрабатывать динамические изменения (локализованные метки, динамический текст и т. Д.).

Я пытался использовать каждую строку какHStack и использование пользовательского выравнивания по меткам:

struct RightAligned: View {
    @State var name = ""
    @State var email = ""
    @State var phone = ""

    var body: some View {
        VStack(alignment: .labelAlign) {
            Row(name: "Name", value: $name)
            Row(name: "Email", value: $email)
            Row(name: "Phone", value: $phone)
        }
        .border(Color.green)
        .padding(30)
    }
}

struct Row: View {
    let name: String
    @Binding var value: String

    var body: some View {
        HStack {
            Text("\(name):")
                .alignmentGuide(.labelAlign, computeValue: { $0[.trailing] })
            TextField(name, text: $value)
        }
    }
}

extension HorizontalAlignment {
    private enum LabelAlign: AlignmentID {
        static func defaultValue(in context: ViewDimensions) -> CGFloat {
            context[.trailing]
        }
    }
    static let labelAlign = HorizontalAlignment(LabelAlign.self)
}

Это выровняет метки, но просто сдвигает HStacks, чтобы они расширялись за пределы содержащего VStack:

enter image description here

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

struct PrefsAlignment: View {
    @State var labelWidth: CGFloat = 100
    @State var name = ""
    @State var email = ""
    @State var phone = ""

    var body: some View {
        VStack(alignment: .leading) {
            PrefsRow(name: "Name", labelWidth: $labelWidth, value: $name)
            PrefsRow(name: "Email", labelWidth: $labelWidth, value: $email)
            PrefsRow(name: "Phone", labelWidth: $labelWidth, value: $phone)
        }
        .onPreferenceChange(LabelPreferenceKey.self) { width in
            self.labelWidth = width
        }
    }
}

struct PrefsRow: View {
    let name: String
    @Binding var labelWidth: CGFloat
    @Binding var value: String

    var body: some View {
        HStack {
            HStack {
                Spacer()
                Text("\(name):")
                    .background(PreferenceSetterView())
            }
            .frame(width: labelWidth)
            TextField(name, text: $value)
                .textFieldStyle(RoundedBorderTextFieldStyle())
        }
    }
}

struct PreferenceSetterView: View {
    var body: some View {
        GeometryReader { proxy in
            Rectangle()
                .fill(Color.clear)
                .preference(key: LabelPreferenceKey.self, value: proxy.size.width)
        }
    }
}


struct LabelPreferenceKey: PreferenceKey {
    static var defaultValue: CGFloat = 0

    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
        value = max(value, nextValue())
    }
}

Это помещает представленияв цикле обратной связи, где предпочтения приводят к изменению кадров метки HStacks, который рекурсивно изменяет предпочтения, и вокруг мы идем, пока ширина не становится равной 0.

Вы можете вручную установить кадры меток всамый широкий, но он хрупкий и не сработает, если он изменится из-за таких вещей, как локализация или динамический тип.

Как в мире вы делаете этот простой макет?

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