Я пытаюсь добиться выравнивания метки по правому краю. Вот пример:
Обратите внимание, что надписи слева выровнены по правому краю. Это кажется простым, но я не нашел способа сделать это в 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:
Также попытался использовать предпочтения для передачи ширины меток родительскому элементу, чтобы я мог сделать все рамки меток одинакового размера:
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.
Вы можете вручную установить кадры меток всамый широкий, но он хрупкий и не сработает, если он изменится из-за таких вещей, как локализация или динамический тип.
Как в мире вы делаете этот простой макет?