Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 751
Jerry Avatar asked Jun 16 '19 00:06

Jerry


People also ask

How do I align a view in SwiftUI?

SwiftUI provides us with the alignmentGuide() modifier for just this purpose. This takes two parameters: the guide we want to change, and a closure that returns a new alignment. The closure is given a ViewDimensions object that contains the width and height of its view, along with the ability to read its various edges.

What is HStack and VStack in SwiftUI?

Individually, HStack , VStack , and ZStack are simple views. HStack positions views in a horizontal line, VStack positions them in a vertical line, and ZStack overlays views on top of one another.

How do I align an image in SwiftUI?

SwiftUI allows us to override standard alignments by using the alignmentGuide modifier. For example, we might need to align the bottom of Image and Text views in a horizontal stack. We can face the problem when image has some spacing inside a bitmap, and it looks not aligned very well.


1 Answers

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

like image 93
tetotechy Avatar answered Sep 29 '22 10:09

tetotechy