在 UITextField 与 UIViewRepresentable 和 SwifUI 之间绑定文本时出现问题

Posted

技术标签:

【中文标题】在 UITextField 与 UIViewRepresentable 和 SwifUI 之间绑定文本时出现问题【英文标题】:Issue when binding text between UITextField with UIViewRepresentable and SwifUI 【发布时间】:2020-07-26 05:31:10 【问题描述】:

我正在尝试在 SwiftUI 中创建一个“表情符号选择器”,它会调出表情符号键盘,允许用户选择一个表情符号,然后关闭键盘。我正在使用带有字符串绑定的 UIViewRepresntable 中包装的 UITextField,但是由于某种原因,字符串的值永远不会更新。

这是我目前的代码:

/// Allows a user to pick an emoji character using the Emoji keyboard.
/// - Note: This does not prevent the user from manually switching to other keyboards and inputting a non-Emoji character
struct EmojiPicker: UIViewRepresentable 
    @Binding var emoji: String
    
    func makeUIView(context: UIViewRepresentableContext<EmojiPicker>) -> EmojiUITextField 
        let textField = EmojiUITextField(frame: .zero)
        textField.text = emoji
        textField.delegate = context.coordinator
        textField.autocorrectionType = .no
        textField.returnKeyType = .done
        textField.textAlignment = .center
        textField.tintColor = .clear
        
        return textField
    
    
    func updateUIView(_ uiView: EmojiUITextField, context: Context) 
        self.emoji = uiView.text!
    
    
    func makeCoordinator() -> EmojiTextFieldCoordinator 
        return EmojiTextFieldCoordinator(self)
    


internal class EmojiTextFieldCoordinator: NSObject, UITextFieldDelegate 
    var emojiTextField: EmojiPicker
    
    init(_ textField: EmojiPicker) 
        self.emojiTextField = textField
    
    
    func textFieldDidEndEditing(_ textField: UITextField) 
        self.emojiTextField.emoji = textField.text!
    
    
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool 
        textField.text = string
        
        if let text = textField.text, text.count == 1 
            self.emojiTextField.emoji = textField.text!
            UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
        
        
        return true
    


internal class EmojiUITextField: UITextField 
    override var textInputContextIdentifier: String? 
        return ""
    

    override var textInputMode: UITextInputMode? 
        return UITextInputMode.activeInputModes.first 
            $0.primaryLanguage == "emoji"
        
    
    
    override func selectionRects(for range: UITextRange) -> [UITextSelectionRect] 
        return []
    

到目前为止我找到的所有资源都没有用,包括this、this和this

【问题讨论】:

【参考方案1】:

这里是修复,唯一修改的部分,(用 Xcode 12 / ios 14 测试)

func updateUIView(_ uiView: EmojiUITextField, context: Context) 
    if self.emoji != uiView.text!      // << update only on change, otherwise
        self.emoji = uiView.text!       // it result in cycle and dropped
    

这是一个用于测试的视图

struct ContentView: View 
    @State private var text = "<none>"
    var body: some View 
        VStack 
            Text("Get: \(text)")
            EmojiPicker(emoji: $text)
        
    

【讨论】:

嗯,它仍然不适合我(我也在使用 iOS 14) 实际上是因为在我的 SwiftUI 预览结构中,我直接使用了@State,而不是使用另一个结构 updateUIView 中的分配感觉倒退了。 updateUIView 不应该获取外部信息(绑定到self.emoji),并更新其外观以匹配?我认为这应该是uiView.text = self.emoji。 (然后你需要使用addTarget 来更新self.emoji 打字发生。)如所写,如果一个表情符号被分配给emoji 绑定,这个视图不会更新,对吧? 这是我一直在根据您的代码处理的示例(但 updateUIView 工作在另一个方向)。 gist.github.com/rnapier/bd3a9a5949fe809f7cd9568d85b3e281

以上是关于在 UITextField 与 UIViewRepresentable 和 SwifUI 之间绑定文本时出现问题的主要内容,如果未能解决你的问题,请参考以下文章

UITextField 清除按钮与屏幕动画一起使用

UITableViewCell 中的 UITextField 与 UIPickerView?

在 UITextField 与 UIViewRepresentable 和 SwifUI 之间绑定文本时出现问题

RunTime 在iOS中的应用与UITextField占位字符placeholder自定义

UITextField - shouldChangeCharactersIn 与 self.addSubview()

UITableView 中的 UITextField 与 DatePicker 的 InputView