【问题标题】:Pass state/binding to UIViewRepresentable将状态/绑定传递给 UIViewRepresentable
【发布时间】:2023-03-10 02:16:01
【问题描述】:

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

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

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

【问题讨论】:

  • 您找到解决方案了吗?

标签: ios swift swift5


【解决方案1】:

在您的CustomTextField 中创建一个@Binding 属性,例如:

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

init() 中初始化您的@Binding 属性,例如:

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

text 属性传递给UITextField,例如:

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

更新UITextFieldtext 喜欢:

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

使用用户输入的文本更新@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
}

您的ContentView 应如下所示:

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

现在好,如果您想要CustomTextField 的完整代码,请查看this answer

【讨论】:

    【解决方案2】:

    似乎绑定文本 (@Binding var text: String) 不会更改,而 TextField 的文本即使在 uiView.text = text 之后也会更改,因此您需要使用闭包手动更新绑定文本以获取包含绑定文本的上下文,TextField的对象和值均等化的代码语句,并使用Delegate自动调用闭包。但是,TextField 的 Delegate(UITextFieldDelegate 类)没有正确反映文本更改的有效方法(func textField 总是在更改之后调用),因此如果使用 Delegate(类),使用 TextView 而不是 TextField 可能会更好TextViewDelegate), 因为它的 Delegate 有 textViewDidChange 方法,在更改 TextView 的文本时肯定会调用该方法。 TextField 或 TextView 的 addTarget 方法不起作用,因为 Obj-C 函数(闭包)不能在 swift struct 中使用。 我尝试了下面的代码: (测试环境: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
        }
    }
    

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

    更新:

    如果您仍想使用 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!
            }
        }
    }
    

    这是适当的语法,它也可以工作,虽然它不能与 TextView 一起工作:它没有方法 addTarget。

    【讨论】:

      猜你喜欢
      • 2019-03-08
      • 2021-11-12
      • 2019-02-17
      • 2020-10-29
      • 1970-01-01
      • 1970-01-01
      • 2019-06-25
      • 2019-08-19
      • 1970-01-01
      相关资源
      最近更新 更多