Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to dynamically add text fields like Contacts with SwiftUI?

Tags:

swiftui

I have a form where I'd like the user to add any amount of promo codes. The closest native example of this is in the Contacts app. See add url section, which I wouldn't need the "homepage" or "home" links but the delete functionality is: enter image description here

How can this be constructed with SwiftUI or is there a more recommended way of handling this scenario? Thanks for any help!

like image 797
TruMan1 Avatar asked Oct 22 '25 07:10

TruMan1


1 Answers

So this is very quick and dirty, but it should give you an idea of a direction to go in:

struct PromoCodeView: View {
    
    @State var codes = [String]()
    
    func getBinding(forIndex index: Int) -> Binding<String> {
        return Binding<String>(get: { codes[index] },
                               set: { codes[index] = $0 })
    }
    
    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("Promo Codes")) {
                    ForEach(0..<codes.count, id: \.self) { index in
                        HStack {
                            Button(action: { codes.remove(at: index) }) {
                                Image(systemName: "minus.circle.fill")
                                    .foregroundColor(.red)
                                    .padding(.horizontal)
                            }
                            TextField("Promo Code", text: getBinding(forIndex: index))
                        }
                    }
                    Button(action: { codes.append("") }) {
                        HStack {
                            Image(systemName: "plus.circle.fill")
                                .foregroundColor(.green)
                                .padding(.horizontal)
                            Text("add promo code")
                        }
                    }
                }
            }
            .navigationBarTitle("Codes")
        }
    }
}

And looks like this:

enter image description here

EDIT:


Okay, so I've made it a lot more generic so you can just drop the view in and give it a binding to your string array:

struct ListEditor: View {
    
    var title: String
    var placeholderText: String
    var addText: String
    @Binding var list: [String]
    
    func getBinding(forIndex index: Int) -> Binding<String> {
        return Binding<String>(get: { list[index] },
                               set: { list[index] = $0 })
    }
    
    
    var body: some View {
        Section(header: Text(title)) {
            ForEach(0..<list.count, id: \.self) { index in
                ListItem(placeholder: placeholderText, text: getBinding(forIndex: index)) { self.list.remove(at: index) }
            }
            AddButton(text: addText) { self.list.append("") }
        }
    }
}

fileprivate struct ListItem: View {
    
    var placeholder: String
    @Binding var text: String
    var removeAction: () -> Void
    
    var body: some View {
        HStack {
            Button(action: removeAction) {
                Image(systemName: "minus.circle.fill")
                    .foregroundColor(.red)
                    .padding(.horizontal)
            }
            TextField(placeholder, text: $text)
        }
    }
    
}

fileprivate struct AddButton: View {
    
    var text: String
    var addAction: () -> Void
    
    var body: some View {
        Button(action: addAction) {
            HStack {
                Image(systemName: "plus.circle.fill")
                    .foregroundColor(.green)
                    .padding(.horizontal)
                Text(text)
            }
        }
    }
}

You can use it like this:

struct TestView: View {
    
    @State var codes = [String]()
    
    var body: some View {
        NavigationView {
            Form {
                ListEditor(title: "Promo Codes",
                           placeholderText: "Promo Code",
                           addText: "add promo code",
                           list: $codes)
            }
            .navigationBarTitle("Codes")
        }
    }
    
}

It looks identical to the above GIF.

like image 95
RogerTheShrubber Avatar answered Oct 24 '25 01:10

RogerTheShrubber



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!