简体   繁体   English

将状态/绑定传递给 UIViewRepresentable

[英]Pass state/binding to UIViewRepresentable

What is the correct way to pass a state variable to my custom text field?将 state 变量传递给我的自定义文本字段的正确方法是什么? I was hoping to avoid other approaches/observables.我希望避免其他方法/可观察的。 Shouldn't this work?这不应该工作吗?

I have recreated the problem below in an example project.我在示例项目中重新创建了以下问题。

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
    }
}

Create a @Binding property in your CustomTextField like:在您的CustomTextField中创建一个@Binding属性,例如:

struct CustomTextField: UIViewRepresentable {
    @Binding var text: String 
}

Initialize your @Binding property in init() like:init()中初始化您的@Binding属性,例如:

init(text: Binding<String>) {
    self._text = text
}

Pass the text property to UITextField like:text属性传递给UITextField ,如:

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

Update the text of UITextField like:更新UITextFieldtext ,如:

func updateUIView(_ uiView: UITextField, context: Context) {
    uiView.text = self.text
}

Update the @Binding property with user entered text like:使用用户输入的文本更新@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
}

Your ContentView should look like:您的ContentView应如下所示:

struct ContentView: View {
    @State var text: String = ""
    var body: some View {
        CustomTextField(text: $text)
    }
}

Ok now if you want full code of the CustomTextField then see this answer .好的,如果您想要CustomTextField的完整代码,请查看此答案

It seems that the binding text ( @Binding var text: String ) won't change while the text of TextField changes even after uiView.text = text , so you need manually update the binding text by using a closure to fetch the context contains the binding text, the object of TextField and the code statement of value equalization, and using Delegate to automatically call the closure.即使在uiView.text = text之后,绑定文本( @Binding var text: String )似乎也不会改变,而 TextField 的文本会发生变化,因此您需要使用闭包手动更新绑定文本以获取包含绑定文本,TextField的object和值均衡的代码语句,并使用Delegate自动调用闭包。 However, the Delegate of TextField (class UITextFieldDelegate) don't have an efficient method that correctly reflects the change of text (func textField is always called later than the change), so using TextView rather than TextField may be better if using Delegate (class TextViewDelegate), because its Delegate has the method textViewDidChange which will be called certainly while changing text of TextView.但是,TextField 的 Delegate(UITextFieldDelegate 类)没有正确反映文本更改的有效方法(func textField 总是在更改之后调用),因此使用 TextView 而不是 TextField 可能会更好TextViewDelegate),因为它的Delegate有方法textViewDidChange,在改变TextView的文本时肯定会调用该方法。 The method addTarget of TextField or TextView won't work because Obj-C functions (the closure) cannot use in swift struct. TextField 或 TextView 的方法 addTarget 将不起作用,因为 Obj-C 函数(闭包)不能在 swift 结构中使用。 I tried code below: (Testing Environment: Xcode 11.4.1, Swift 5.2.2)我尝试了以下代码:(测试环境:Xcode 11.4.1,Swift 5.2.2)

//Add new:
var bindingUpdate:()->Void={}  //the definition the closure

//Add new:
class TextViewDelegate:UIViewController,UITextViewDelegate{
    func textViewDidChange(_ textView: UITextView) {
        bindingUpdate()  //call the closure while text changed
    }
}

//Modify:
struct MyTextView: UIViewRepresentable {
    @Binding var text: String
    var delegate=TextViewDelegate()
    func makeUIView(context: Context) -> UITextView {
        let view = UITextView()
        view.font=UIFont(name: "Helvetica", size: 18)
        view.layer.borderWidth = 2;
        view.layer.cornerRadius = 16;
        view.delegate=delegate
        bindingUpdate={  //the closure
            self.text=view.text
            //add other lines here if you want make other effects while text changed
        }
        return view
    }
    func updateUIView(_ uiView: UITextView, context: Context) {
        uiView.text = text
    }
}

I'm not sure if the grammar is appropriate but it works fine我不确定语法是否合适,但效果很好

Update:更新:

This is a better way if you still want to use TextField: you could use Coordinator to update the binding text.如果您仍想使用 TextField,这是一种更好的方法:您可以使用 Coordinator 来更新绑定文本。

struct MyTextField: 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) {
        uiView.text = text
    }
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    class Coordinator: NSObject{
        var myView: MyTextField

        init(_ view: MyTextField){
            self.myView=view
        }
        @objc func updateText(sender: UITextField){
            myView.text=sender.text!
        }
    }
}

This is the appropriate grammar and it works too, although it can't work with TextView: it don't have method addTarget.这是适当的语法,它也可以工作,虽然它不能与 TextView 一起工作:它没有方法 addTarget。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM