2

Is this layout possible with SwiftUI?

I want the first column to wrap the size of the labels, so in this case it will be just big enough to show "Bigger Label:". Then give the rest of the space to the second column.

This layout is pretty simple with auto layout.

SwiftUI 2020 has LazyVGrid but the only ways I see to set the column sizes use hardcoded numbers. Do they not understand what a problem that causes with multiple languages and user-adjustable font sizes?

Rob N
  • 11,371
  • 11
  • 72
  • 126

1 Answers1

2

It is not so complex if to compare number of code lines to make this programmatically in both worlds...

Anyway, sure it is possible. Here is a solution based on some help modifier using view preferences feature. No hard. No grid.

Demo prepared & tested with Xcode 12 / iOS 14.

demo

struct DemoView: View {
    @State private var width = CGFloat.zero

    var body: some View {
        VStack {
            HStack {
                Text("Label1")
                    .alignedView(width: $width)
                TextField("", text: .constant("")).border(Color.black)
            }
            HStack {
                Text("Bigger Label")
                    .alignedView(width: $width)
                TextField("", text: .constant("")).border(Color.black)
            }
        }
    }
}

and helpers

extension View {
    func alignedView(width: Binding<CGFloat>) -> some View {
        self.modifier(AlignedWidthView(width: width))
    }
}

struct AlignedWidthView: ViewModifier {
    @Binding var width: CGFloat

    func body(content: Content) -> some View {
        content
            .background(GeometryReader {
                Color.clear
                    .preference(key: ViewWidthKey.self, value: $0.frame(in: .local).size.width)
            })
            .onPreferenceChange(ViewWidthKey.self) {
                if $0 > self.width {
                    self.width = $0
                }
            }
            .frame(minWidth: width, alignment: .trailing)
    }
}
Asperi
  • 123,447
  • 8
  • 131
  • 245
  • Thank you, I'll accept this answer, but I'm curious... has Apple ever documented or said anything about using preferences this way? (To effectively pass geometric constraints *up* the view hierarchy?) When people started doing this last year, my impression was that it was a hack, a clever abuse of preferences to make up for a missing feature. (If I remember right it sometimes generates warning messages in my console.) I thought SwiftUI 2020 would address this, but ... I didn't hear anything about it in WWDC videos. Have you? – Rob N Sep 21 '20 at 19:32
  • @RobN From what I've read, it seems like this is exactly the kind of thing that SwiftUI "preferences" are for. It's just a confusing name. I think of them as a bottom-up counterpart to environment values which are top-down. – Uncommon Feb 11 '21 at 23:48
  • This answer got me partway to what I need. The left side labels are getting sized correctly, but my right column also needs to be sized to fit its content, and instead it gets cut off depending on how the labels were resized. – Uncommon Feb 12 '21 at 00:01
  • 1
    @Uncommon It seems they were designed for passing _values_ upward, yes, but I doubt they were designed for _constraints_, which SwiftUI is sorely missing, in my opinion. For example, this answer does not work if the Views change size, which is common. (Eg, the text content changes.) – Rob N Mar 20 '21 at 16:28