I feel like I'm misunderstanding how Binding
works in SwiftUI, in that I do not understand why the first TextField
below does not update when the text
view model property changes:
class MyViewModel: ObservableObject {
@Published var text: String = "Hello"
var binding: Binding<String>!
init() {
binding = Binding(get: { self.text }, set: { self.text = $0 })
}
}
struct MyView: View {
@StateObject var viewModel = MyViewModel()
var body: some View {
VStack {
Text("Actual: " + viewModel.text)
TextField("Field 1", text: viewModel.binding)
TextField("Field 2", text: $viewModel.text)
}
}
}
struct MyView_Previews: PreviewProvider {
static var previews: some View {
MyView()
}
}
Typing in the first TextField
always updates second one (and the Text
label), but typing in the second TextField
only propagates changes to the Text
label, shown here:
In my actual use case, the list of TextField
views is dynamically generated from a user-defined template, likewise with custom bindings to a @Published
complex object (ie not as simple as a String
) on MyViewModel
. In my limited experience, I believe the dynamic nature of the view prevents me from coding it in a straight-forward fashion, as seen with the second TextField
.
My guess is that SwiftUI has no insight that the custom binding should even need to be refreshed, in which case my question becomes: How can I tell the binding to "refresh" the TextField
while also supporting dynamically-generated content?
First, consider this line code
binding = Binding(get: { self.text }, set: { self.text = $0 })
You are assigning binding value to self.text
by self.text = $0
, it means now self.text
value updated and your view is rendering with new value so, it will display with new value in the all place.
Now, you are changing the value of @Published
var by the second field. when you are changing this var, your just changing the value of @Published var text: String
this var and it's not related to this binding var var binding: Binding<String>!
there is no communication or connection. so var binding: Binding<String>!
value is not changed and remains the same as the old value.
If you want to update both directions, you also need to add this code
@Published var text: String = "Hello" {
didSet {
binding = Binding(get: { self.text }, set: { self.text = $0 }) // <-- Here
}
}
So now it will reflect on both sides.
If you have still confusion Replace this line
var binding: Binding<String>!
with this
@Published var binding: String = ""
And now think. The above way is the same way as your code, just have a different declaration. These are now two different var but doing the same things.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.