将状态/绑定传递给 UIViewRepresentable

Bry*_*tts 10 ios swift swift5

将状态变量传递到自定义文本字段的正确方法是什么?我希望避免其他方法/观察结果。这不应该起作用吗?

我在示例项目中重新创建了下面的问题。

import SwiftUI

struct ParentView: View {
    @State var text: String = "initial"
    var body: some View {
        VStack {
            ChildView(text: $text)
            Text(self.text)
        }
    }
}
struct ChildView: View {
    @Binding var text: String
    var body: some View {
        MyTextField(text: $text).frame(width: 300, height: 40, alignment: .center)
    }
}

struct MyTextField: UIViewRepresentable {
    @Binding var text: String
    func makeUIView(context: Context) -> UITextField {
        let view = UITextField()
        view.borderStyle = UITextField.BorderStyle.roundedRect
        return view
    }
    func updateUIView(_ uiView: UITextField, context: Context) {
        uiView.text = text
    }
}
Run Code Online (Sandbox Code Playgroud)

Md.*_*lah 15

创建一个@Binding你喜欢的属性CustomTextField

struct CustomTextField: UIViewRepresentable {
    @Binding var text: String 
}
Run Code Online (Sandbox Code Playgroud)

初始化你的@Binding财产,init()如:

init(text: Binding<String>) {
    self._text = text
}
Run Code Online (Sandbox Code Playgroud)

text属性传递给UITextFieldlike:

func makeUIView(context: Context) -> UITextField {
    // Customise the TextField as you wish
    textField.text = text        
    return textField
}
Run Code Online (Sandbox Code Playgroud)

更新text如下UITextField

func updateUIView(_ uiView: UITextField, context: Context) {
    uiView.text = self.text
}
Run Code Online (Sandbox Code Playgroud)

@Binding使用用户输入的文本更新属性,例如:

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    if let value = textField.text as NSString? {
    let proposedValue = value.replacingCharacters(in: range, with: string)
        parent.text = proposedValue as String // Here is updating
    }
    return true
}
Run Code Online (Sandbox Code Playgroud)

你的ContentView应该看起来像:

struct ContentView: View {
    @State var text: String = ""
    var body: some View {
        CustomTextField(text: $text)
    }
}
Run Code Online (Sandbox Code Playgroud)

好吧,现在如果您想要完整的代码,CustomTextField请参阅此答案


小智 1

看起来绑定文本 ( @Binding var text: String) 不会改变,而 TextField 的文本即使在 之后发生变化uiView.text = text,因此您需要通过使用闭包来获取包含绑定文本、TextField 对象和代码的上下文来手动更新绑定文本声明值均衡,并使用Delegate自动调用闭包。但是,TextField 的 Delegate(UITextFieldDelegate 类)没有有效的方法来正确反映文本的更改(func textField 总是在更改之后调用),因此如果使用 Delegate ( class TextViewDelegate),因为它的Delegate有textViewDidChange方法,当改变TextView的文本时肯定会调用这个方法。TextField 或 TextView 的 addTarget 方法将不起作用,因为 Obj-C 函数(闭包)无法在 swift 结构中使用。\n我尝试了以下代码:\n(测试环境:Xcode 11.4.1,Swift 5.2.2\xef \xbc\x89

\n\n
//Add new:\nvar bindingUpdate:()->Void={}  //the definition the closure\n\n//Add new:\nclass TextViewDelegate:UIViewController,UITextViewDelegate{\n    func textViewDidChange(_ textView: UITextView) {\n        bindingUpdate()  //call the closure while text changed\n    }\n}\n\n//Modify:\nstruct MyTextView: UIViewRepresentable {\n    @Binding var text: String\n    var delegate=TextViewDelegate()\n    func makeUIView(context: Context) -> UITextView {\n        let view = UITextView()\n        view.font=UIFont(name: "Helvetica", size: 18)\n        view.layer.borderWidth = 2;\n        view.layer.cornerRadius = 16;\n        view.delegate=delegate\n        bindingUpdate={  //the closure\n            self.text=view.text\n            //add other lines here if you want make other effects while text changed\n        }\n        return view\n    }\n    func updateUIView(_ uiView: UITextView, context: Context) {\n        uiView.text = text\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

我不确定语法是否合适\n但效果很好

\n\n

更新\xef\xbc\x9a

\n\n

如果您仍然想使用 TextField,这是一个更好的方法:您可以使用 Coordinator 来更新绑定文本。

\n\n
struct MyTextField: UIViewRepresentable {\n    @Binding var text: String\n    func makeUIView(context: Context) -> UITextField {\n        let view = UITextField()\n        view.borderStyle = .roundedRect\n        view.addTarget(\n            context.coordinator,\n            action: #selector(Coordinator.updateText(sender:)),\n            for: .editingChanged\n        )\n        return view\n    }\n    func updateUIView(_ uiView: UITextField, context: Context) {\n        uiView.text = text\n    }\n    func makeCoordinator() -> Coordinator {\n        Coordinator(self)\n    }\n    class Coordinator: NSObject{\n        var myView: MyTextField\n\n        init(_ view: MyTextField){\n            self.myView=view\n        }\n        @objc func updateText(sender: UITextField){\n            myView.text=sender.text!\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是适当的语法,它也有效,尽管它不能与 TextView 一起使用:它没有 addTarget 方法。

\n