简体   繁体   English

在 UITextFieldViewRepresentable 中设置.onCommit{} SwiftUI

[英]Setting up .onCommit{} in UITextFieldViewRepresentable SwiftUI

I bridge UIKit with SwiftUI as follows:我将 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
        }
    }
}

And call it as follows:并按如下方式调用它:

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

This works fine in some parts of my app.这在我的应用程序的某些部分工作正常。 In other parts, I need a text field which calls a method when the user taps the enter key after entering text.在其他部分,我需要一个文本字段,当用户在输入文本后点击回车键时调用一个方法。 It's written like this:是这样写的:

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

I tried implementing the above with UITextFieldViewRepresenatable as follows:我尝试使用 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()
           }
    })

I'm getting 'compiler couldn't type check this expression in reasonable time' error.我收到“编译器无法在合理的时间内检查此表达式的类型”错误。 I think I've narrowed it down to not implementing.onCommit:{} in my UITextFieldViewRepresentable()我想我已经将范围缩小到不在我的 UITextFieldViewRepresentable() 中执行 .onCommit:{}

If this is the problem, then I'd like to know how.onCommit:{} can be implemented in UITextFieldViewRepresentable().如果这是问题所在,那么我想知道如何在 UITextFieldViewRepresentable() 中实现 onCommit:{}。

There are a few mistakes in the UIViewRepresentable implementation: UIViewRepresentable 实现中有一些错误:

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

This text binding will be out of date when the View is recreated, so change it to:重新创建视图时,此文本绑定将过时,因此将其更改为:

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

You can store the textField inside the coordinator, make it a lazy, set delegate self, then return it from the make func, eg..您可以将 textField 存储在协调器中,使其成为惰性的,设置委托自我,然后从 make func 返回它,例如..

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

In update, you need to make use of the new value of the binding, eg在更新中,您需要使用绑定的新值,例如

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

You'll see something similar in PaymentButton.swift in Apple's Fruta sample .您会在 Apple 的Fruta 示例中的 PaymentButton.swift 中看到类似的内容。

Perhaps a simpler way would be this (but I've not tested it yet):也许更简单的方法是这样(但我还没有测试过):

// update
context.coordinator.textBinding = _text

// Coordinator
var textBinding: Binding<String>?

// textViewDidChange
textBinding?.wrappedValue = textField.text

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

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