SwiftUI TextField with vertical axis does not align to firstTextBaseline when text is empty

155 Views Asked by At

I have a difficult time to find a workaround to align multiline TextField with another Text in HStack. I want to align it firstTextBaseline. The problem is, TextField jumps down when its text becomes empty and only the placeholder is shown.

I use these HStack in the List rows, but the alignment does not work even in the stripped and simplified code like this:

struct TextFieldAlignmentProblem: View {
    
    @State private var text: String = ""
    
    var body: some View {
        HStack(alignment: .firstTextBaseline) {
            Text("1")
            TextField("Text", text: $text, axis: .vertical)
        }
        .padding()
    }
}

TextField jumps down when its text becomes empty and only the placeholder is shown.

If I remove axis: .vertical or use .center alignment instead of .firstTextBaseline, the jumping problem disappears, but that is not the layout I need.

The problem looks quite simple, but I failed to find a suiting solution for now.

1

There are 1 best solutions below

2
Mojtaba Hosseini On BEST ANSWER

Unfortunately, it's a bug that happens on the axis: .vertical when the field is empty.

✅ Perfect Solution:

You can make a placeholder to hold the textfield in the correct position:

struct TextFieldAlignmentProblem: View {

    @State private var text: String = ""
    private var placeholder: String { text.isEmpty ? " " : text } //  Generate a correct placeholder. I have used a single space.

    var body: some View {
        HStack(alignment: .firstTextBaseline) {
            Text("1")

            TextField("Text", text: .constant(placeholder), axis: .vertical) //  Use the placeholder as the base
                .opacity(0) //  Make it hidden keeping the frame
                .overlay { //  Put the actual TextField on top of the placeholder view
                    TextField("Text", text: $text, axis: .vertical)
                }
        }
        .padding()
    }
}

Simple Solution:

If you are not going to use different fonts, typefaces, dynamic types, etc, a very simple and quick workaround could be checking the condition and passing the (visually) correct alignment:

HStack(
    alignment: text.isEmpty ? .center : .firstTextBaseline //  Conditional alignment
) { ,,, }