Search code examples
swiftuialignmenttextfield

TextField alignment in Form and HStack


I want to show a Form with a HStack in it. In this HStack I have a Text and a TextField. The TextField should align on the right side, the text on the left. I've tried it with Spacers, with the TextBaseline, with Grids but nothing worked.

struct GeschenkeDetailView: View {
    
    @State private var anzahlItems: Int = 0
    @State private var showArrivedAlert: Bool = false
    @State private var showDeleteAlert: Bool = false
    
    @Binding var personName: String
    @Binding var items: [GeschenkItem]
    
    
    var body: some View {
        Form {
            Section("Für wen ist das Geschenk?") {
                TextField("Name", text: $personName)
                    .bold()
            }
            
            ForEach(items.indices, id: \.self) { index in
                let item = items[index]
                
                Section("Produkt \(anzahlItems + index + 1)") {
                    
                    HStack {
                        Text("Produkt:")
                        Spacer()
                        //Text(item.name)
                        TextField("Produktname", text: $items[index].name)
                            .aspectRatio(contentMode: .fit)
                    }
                    
                    Picker("Status:", selection: $items[index].status) {
                        ForEach(Status.allCases, id: \.self) { status in
                            Text(status.asString).tag(status)
                        }
                    }
                    .pickerStyle(.menu)
                    .accentColor(item.status.color)
                    
                    HStack {
                        Text("Preis:")
                        Spacer()
                        Text("\(item.preis)€")
                    }
                    
                    LazyVGrid(columns: [GridItem(), GridItem()]) {
                        Button(action: {
                            showArrivedAlert = true
                        }, label: {
                            Text("Produkt angekommen")
                                .multilineTextAlignment(.center)
                                .foregroundStyle(.green)
                        })
                        .buttonStyle(BorderlessButtonStyle())
                        
                        Button(action: {
                            showDeleteAlert = true
                        }, label: {
                            Text("Produkt löschen")
                                .multilineTextAlignment(.center)
                                .foregroundStyle(.red)
                        })
                        .buttonStyle(BorderlessButtonStyle())
                        
                    }
                }
            }
            
            Section {
                Button(action: {}, label: {
                    Text("Angekommene Produkte")
                })
            }
            .frame(maxWidth: .infinity)
            
            Section {
                Button("Person löschen", role: .destructive) {
                    
                }
            }
            .frame(maxWidth: .infinity)
            
        }
        .alert("Produkt angekommen?", isPresented: $showArrivedAlert) {
            Button("Abbrechen") {
                
            }
            
            Button(action: {}, label: {
                Text("Angekommen")
                    .bold()
            })
            
        } message: {
            Text("Sie können diese Produkte jederzeit erneut einsehen und wiederherstellen.")
        }
        
        .alert("Produkt löschen?", isPresented: $showDeleteAlert) {
            Button("Behalten", role: .cancel) {
                
            }
            
            Button("Löschen", role: .destructive) {
                
            }
            
        } message: {
            Text("Bist du dir sicher das du dieses Produkt löschen möchtest?")
        }
        
    }
}

I made it with a fixed size of the Textfield, but then the textfield was to small. It was about 50 frame. I want the textfield to align on the right side and when the user is typing something it should expand to the left side. It is about the "Produkt:" component. enter image description here


Solution

  • The alignment of the text inside the TextField can be controlled by applying .multilineTextAlignment.

    You want the alignment to be .leading when the field has focus, but .trailing at other times. This means, you need to detect when the field has focus. A FocusState variable can be used for this.

    @FocusState private var focusedField: Int?
    

    Then you just need to change the HStack that contains the field to the following:

    HStack {
        Text("Produkt:")
        TextField("Produktname", text: $items[index].name)
            .focused($focusedField, equals: index)
            .multilineTextAlignment(focusedField == index ? .leading : .trailing)
    }
    

    Animation