Cesare
Cesare

Reputation: 9419

Subclassing TextField and passing state to it in SwiftUI

I'm trying to subclass a TextField to clean up the code. I currently have one text field "row" in my Form, but eventually I would like to find a way to make this scalable (and have a lot more HStacks).

Form {
    Section {
        HStack {
            Text("Balance")
                .foregroundColor(Color.white)
            TextField("", text: $balance, onEditingChanged: { (changing) in
                print("Changing: \(changing)")
            }, onCommit: {
                print("Committed!")
            })
            .multilineTextAlignment(.trailing)
            .foregroundColor(Color.white)
            .keyboardType(.numbersAndPunctuation)
            .onReceive(Just(balance)) { newValue in
                    let filtered = newValue.filter { "0123456789".contains($0) }
                    if filtered != newValue {
                        self.balance = filtered
                }
            }
            .placeHolder(
                Text("$0.00")
                    .frame(maxWidth: .infinity, alignment: .trailing)
                    .multilineTextAlignment(.trailing)
                    .foregroundColor(Color(#colorLiteral(red: 0.3492315412, green: 0.3486715555, blue: 0.3704651594, alpha: 1))),
                show: balance.isEmpty)
        }
    }
    .listRowBackground(Color(#colorLiteral(red: 0.1923851669, green: 0.1917944849, blue: 0.2135801911, alpha: 1)))
}

I don't want to repeat the HStack declaration 4 times (the number of rows). So I need to subclass. However, I need to find a way to pass the state (dollar sign) to the subclass. How? Also, is there any way to have an array of states so that I can use a ForEach? Example:

var imaginaryArrayWithStates = [$textFieldValue1, $textFieldValue2] // you can't do this, but I would like to iterate states somehow...

// ...so that I can use a ForEach
ForEach(imaginaryArrayWithStates) { state
    MyCustomTextField() // how do I pass the state to this subclass? 
}

Upvotes: 1

Views: 681

Answers (1)

pawello2222
pawello2222

Reputation: 54611

You can use @Binding:

struct CustomTextField: View {
    @Binding var value: String

    var body: some View {
        HStack {
            Text("Balance") // can be extracted as a variable
            TextField("", text: $value, onEditingChanged: { changing in
                print("Changing: \(changing)")
            }, onCommit: {
                print("Committed!")
            })
                .multilineTextAlignment(.trailing)
                .keyboardType(.numbersAndPunctuation)
                .onReceive(Just(value)) { newValue in
                    let filtered = newValue.filter { "0123456789".contains($0) }
                    if filtered != newValue {
                        self.value = filtered
                    }
                }
        }
    }
}
struct ContentView: View {
    @State var values = ["312", "222", ""]

    var body: some View {
        Form {
            Section {
                ForEach(values.indices, id: \.self) { index in
                    CustomTextField(value: self.$values[index])
                }
            }
        }
    }
}

Upvotes: 2

Related Questions