SwiftUI grid with column that fits content?

1.1k views Asked by At

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?

1

There are 1 answers

4
Asperi On

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)
    }
}