Reputation: 91
I have been writing a UIViewRepresentable and noticing some curios effects in regards to a binding I'm passing into the view. When I read the bindings value in the coordinator through the saved UIViewRepresentable the value is always the value that it was initialized with. Trying to update the same binding however triggers an update in the surrounding UI.
This is code produces this behavior:
struct NativeTextView: UIViewRepresentable {
@Binding var text: String
func makeUIView(context: Context) -> UITextField {
let view = UITextField()
view.borderStyle = .roundedRect
view.addTarget(
context.coordinator,
action: #selector(Coordinator.updateText(sender:)),
for: .editingChanged
)
return view
}
func updateUIView(_ uiView: UITextField, context: Context) {
context.coordinator.updateUI(uiView)
}
func makeCoordinator() -> Coordinator {
Coordinator(_text)
}
class Coordinator: NSObject {
@Binding var text: String
init(_ text: Binding<String>){
_text = text
}
@objc func updateText(sender: UITextField){
text=sender.text!
}
func updateUI(_ uiView: UITextField) {
uiView.text = text
}
}
}
If I hover give my updateUI method a NativeTextView parameter, and use the .text field of it through the parameter, I read the correct value and the UI works correctly:
struct NativeTextView: UIViewRepresentable {
@Binding var text: String
func makeUIView(context: Context) -> UITextField {
let view = UITextField()
view.borderStyle = .roundedRect
view.addTarget(
context.coordinator,
action: #selector(Coordinator.updateText(sender:)),
for: .editingChanged
)
return view
}
func updateUIView(_ uiView: UITextField, context: Context) {
context.coordinator.updateUI(uiView, view: self)
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject {
var myView: NativeTextView
init(_ view: NativeTextView){
self.myView=view
}
@objc func updateText(sender: UITextField){
myView.text=sender.text!
}
func updateUI(_ uiView: UITextField, view: NativeTextView) {
uiView.text = view.text
}
}
}
It seems that the binding retains the ability to write to the outside @State variable but does not manage to access the current states value correctly. I'm guessing that this has something to do with the recreation of the NativeTextView view when SwiftUI notices an update of the @State, but I have not been able to find any documentation that would explain this behavior. Does anyone know why this happens?
PS: for completeness this is my ContentViews body:
ZStack {
Color.red
VStack {
Text(test)
.padding()
.onTapGesture() {
test = "Bla"
}
NativeTextView(text: $test)
}
}
Upvotes: 4
Views: 1069
Reputation: 30746
It's because you only give the binding to the Coordinator
once, here:
func makeCoordinator() -> Coordinator {
Coordinator(_text)
}
The text binding is a value that is changed every time the NativeTextView
UIViewRepresentable
is re-init by the parent View's body, so you need to give the new value of the binding to the coordinator in update
. So you can do:
func updateUIView(_ uiView: UITextField, context: Context) {
context.coordinator._text = _text
}
Upvotes: -1
Reputation: 11
Coordinator in swiftui is like delegate, so you update your view with bind value in updateUIView like this: uiView.text = text, and you don't need updateUI method in Coordinator (view.text has your initial text in it in that method)
Upvotes: 1