I'm new to Swift and SwiftUI and have a model with a @Published intValue optional and a view with a TextField where its text/string property is 2-way bound to intValue of the model. Need to make sure valid text entry as a string is converted to a valid integer for the model. What is the recommended approach to handle this in SwiftUI? Code is similar to below...
//Model
class AppModel:ObservedObject {
@Published
var intValue: Int? = 5
}
//View
@ObservedObject
var appModel = AppModel.shared
TextField("", text: $appModel.intValue)
.keyboardType(.numberPad)
Updated sample code...
///////////
import SwiftUI
class Model: ObservableObject {
static var shared: Model = Model()
@Published
var number: Int = 0
init(){}
}
struct ContentView: View {
var body: some View {
TextFieldFormatter()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct TextFieldFormatter: View {
@ObservedObject
var model: Model = Model.shared
@State private var number: Int = 0
let formatter: NumberFormatter = {
let numFormatter = NumberFormatter()
numFormatter.numberStyle = .none
return numFormatter
}()
var body: some View {
VStack {
Text("State").onTapGesture {
self.endEditing()
}
TextField("int", value: $number, formatter: formatter).keyboardType(.numberPad)
Text("Echo: \(number)")
Text("Observable")
TextField("int", value: $model.number, formatter: formatter).keyboardType(.numberPad)
Text("Echo: \(model.number)")
}
}
}
struct TextFieldFormatter_Previews: PreviewProvider {
static var previews: some View {
TextFieldFormatter()
}
}
extension View {
func endEditing() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to:nil, from:nil, for:nil)
}
}
You can create a custom Binding
to pass in to the TextField
.
This is how to construct a Binding<String>
(what the TextField
needs):
var string = ""
let myBinding = Binding(get: { string }) {
string = $0
}
The first argument of the Binding
constructor is the getter. This closure should return a value of the desired type.
The second argument is a setter. It is a closure that takes in the new value, and does something with it (usually set another value).
So, if you want to create a Binding<String>
to pass in to the TextField
that gets/sets appModel.intValue
, you can create a Binding<String>
and pass it into the TextField
like this:
TextField("", text: .init(
get: { self.appModel.intValue.map(String.init) ?? "" },
set: { self.appModel.intValue = Int($0) }
))
.keyboardType(.numberPad)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With