Search code examples
alignmentswiftui

Layout in SwiftUI with horizontal and vertical alignment


I'm trying to accomplish this layout

desired layout

If I try HStack wrapped in VStack, I get this:

HStack in VStack

If I try VStack wrapped in HStack, I get this:

VStack in HStack

Is there a way to baseline align the text with the textfield and get standard spacing from the longest label to the start of the aligned textfields?


Solution

  • not an expert here, but I managed to achieve the desired layout by (1) opting for the 2-VStacks-in-a-HStack alternative, (2) framing the external labels, (3) freeing them from their default vertical expansion constraint by assigning their maxHeight = .infinity and (4) fixing the height of the HStack

    struct ContentView: View {
        @State var text = ""
        let labels = ["Username", "Email", "Password"]
    
        var body: some View {
            HStack {
                VStack(alignment: .leading) {
                    ForEach(labels, id: \.self) { label in
                        Text(label)
                            .frame(maxHeight: .infinity)
                            .padding(.bottom, 4)
                    }
                }
    
                VStack {
                    ForEach(labels, id: \.self) { label in
                        TextField(label, text: self.$text)
                            .textFieldStyle(RoundedBorderTextFieldStyle())
                    }
                }
                .padding(.leading)
            }
            .padding(.horizontal)
            .fixedSize(horizontal: false, vertical: true)
        }
    }
    

    Here is the resulting preview:

    enter image description here

    in order to account for the misaligned baselines of the external and internal labels (a collateral issue that is not related to this specific layout – see for instance this discussion) I manually added the padding

    credits to this website for enlightening me on the path to understanding SwiftUI layout trickeries