【问题标题】:Setting up .onCommit{} in UITextFieldViewRepresentable SwiftUI在 UITextFieldViewRepresentable SwiftUI 中设置 .onCommit{}
【发布时间】:2023-01-25 03:07:06
【问题描述】:

我将 UIKit 与 SwiftUI 桥接如下:

struct UITextFieldViewRepresentable: UIViewRepresentable {

    @Binding var language: String
    @Binding var text: String

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

    func makeUIView(context: Context) -> UITextField {

        let textField = getTextField()
        textField.delegate = context.coordinator

        return textField
    }

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

        // Change the language in the wordTextField here.
        
        if let wordTextField = uiView as? WordTextField {
            wordTextField.language = self.language
        }
    }


    private func getTextField() -> UITextField {

        let textField = WordTextField(frame: .zero)
        textField.language = self.language
        textField.textAlignment = .center
        textField.font = UIFont.systemFont(ofSize: 15, weight: .regular)
        
        return textField
    }

    func makeCoordinator() -> Coordinator {
        return Coordinator(text: $text)
    }

    class Coordinator: NSObject, UITextFieldDelegate {

        @Binding var text: String

        init(text: Binding<String>) {
            self._text = text
        }
        func textFieldDidChangeSelection(_ textField: UITextField) {
            text = textField.text ?? ""
        }
    }

    class WordTextField: UITextField {

        var language: String? {
            didSet {
                if self.isFirstResponder{
                    self.resignFirstResponder()
                    self.becomeFirstResponder()
                }
            }
        }

        override var textInputMode: UITextInputMode? {
            if let language = self.language {
                print("text input mode: \(language)")
                for inputMode in UITextInputMode.activeInputModes {
                    if let inputModeLanguage = inputMode.primaryLanguage, inputModeLanguage == language {
                        return inputMode
                    }
                }
            }
            return super.textInputMode
        }
    }
}

并按如下方式调用它:

UITextFieldViewRepresentable(language: $keyboardLanguage, text: $foreignThing)

这在我的应用程序的某些部分工作正常。在其他部分,我需要一个文本字段,当用户在输入文本后点击回车键时调用一个方法。是这样写的:

TextField("", text: Binding<String>(
    get: { self.userAnswer },
    set: {
           self.userAnswer = $0
           self.enableHint()
    }), onCommit: {
           if self.userAnswer.isEmpty {
               answerPlaceholder = NSMutableAttributedString(string: "Tap here to answer...")
           } else {
               answerDisabled = true
               checkAnswer()
           }
    })

我尝试使用 UITextFieldViewRepresenatable 实现上述内容,如下所示:

UITextFieldViewRepresentable(language: $keyboardLanguage, text: Binding<String>(
    get: { self.userAnswer },
    set: {
           self.userAnswer = $0
           self.enableHint()
    }), onCommit: {
           if self.userAnswer.isEmpty {
               answerPlaceholder = NSMutableAttributedString(string: "Tap here to answer...")
           } else {
               answerDisabled = true
               checkAnswer()
           }
    })

我收到“编译器无法在合理的时间内检查此表达式的类型”错误。我想我已经缩小到不在我的 UITextFieldViewRepresentable() 中实现 .onCommit:{}

如果这是问题所在,那么我想知道如何在 UITextFieldViewRepresentable() 中实现 .onCommit:{}。

【问题讨论】:

    标签: swiftui uikit textfield uiviewrepresentable


    【解决方案1】:

    UIViewRepresentable 实现中有一些错误:

    func makeCoordinator() -> Coordinator {
        return Coordinator(text: $text)
    }
    

    重新创建视图时,此文本绑定将过时,因此将其更改为:

    func makeCoordinator() -> Coordinator {
        return Coordinator()
    }
    

    您可以将 textField 存储在协调器中,使其成为惰性的,设置委托自我,然后从 make func 返回它,例如..

    func makeUIView(context: Context) -> UITextField {
        context.coordinator.textField // lazy property that sets delegate self.
    }
    

    在更新中,您需要使用绑定的新值,例如

    func updateUIView(_ uiView: UITextField, context: Context) {
        uiView.text = text
    
        // Change the language in the wordTextField here.
        
        if let wordTextField = uiView as? WordTextField {
            wordTextField.language = self.language
        }
    
        // use the new binding
        context.coordinator.textDidChange = { newText in
            text = newText
        } 
    }
    
    class Coordinator: NSObject, UITextFieldDelegate {
    
        lazy var textField: UITextField = {
            let textField = UITextField()
            textField.delegate = self
            return textField
        }()
        
        var textDidChange: ((String) -> Void)?
        
        func textFieldDidChangeSelection(_ textField: UITextField) {
            textDidChange?(textField.text)
        }
    }
    

    您会在 Apple 的 Fruta sample 的 PaymentButton.swift 中看到类似的内容。

    也许更简单的方法是这样(但我还没有测试过):

    // update
    context.coordinator.textBinding = _text
    
    // Coordinator
    var textBinding: Binding<String>?
    
    // textViewDidChange
    textBinding?.wrappedValue = textField.text
    

    【讨论】:

      猜你喜欢
      • 2022-11-01
      • 1970-01-01
      • 2020-03-08
      • 1970-01-01
      • 1970-01-01
      • 2022-01-04
      • 2019-10-22
      • 1970-01-01
      相关资源
      最近更新 更多