【问题标题】:Handling UIResponder for UITextView in SwiftUI在 SwiftUI 中处理 UITextView 的 UIResponder
【发布时间】:2020-07-26 19:44:15
【问题描述】:

我正在尝试为 SwiftUI 中 UITextView 的现有子类处理 UIResponder。我已经能够使用协调器模式来处理UITextViewDelegate,但我遇到了UIResponder 的问题。

在过去(使用 UIKit),我会使用 NotificationCenterUIViewController 的子类中为 UIResponder.keyboardWillShowNotification 添加观察者。

在 SwiftUI 中,我不知道该放在哪里。我做了一个简单的事情,就是在makeUIView中重用Coordinator类,如下:

    let nc = NotificationCenter.default
    nc.addObserver(context.coordinator, selector: #selector(Coordinator.keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: editorTextView)

但是keyboardWillShow 方法永远不会被调用。我做错了吗?

【问题讨论】:

    标签: swift swiftui uiresponder


    【解决方案1】:

    我建议您使用组合发布器,这样您就不需要弄乱选择器,但这应该可以。观察者/选择器模式在这个例子中被注释掉了,但是如果你取消它的注释,观察者和发布者都应该在键盘出现时做出响应。

        import Combine
        import SwiftUI
        import UIKit
    
        struct MyTextView: UIViewRepresentable {
        // Pass in the binding to the string from the SwiftUI view
        var text: Binding<String>
    
        init(text: Binding<String>) {
            self.text = text
        }
    
        func makeUIView(context: Context) -> UITextField {
            let tf = UITextField()
            tf.delegate = context.coordinator
            tf.text = context.coordinator.text.wrappedValue // Access the wrapped value in the binding
            return tf
        }
    
        func updateUIView(_ uiView: UITextField, context: Context) {
            //
        }
    
        func makeCoordinator() -> MyTextViewDelegate {
            let delegate = MyTextViewDelegate(text: text)
            return delegate
        }
    
        class MyTextViewDelegate: NSObject, UITextFieldDelegate {
    //      let nc = NotificationCenter.default
            var text: Binding<String>
    
            // You can use a Combine Publisher rather than dealing with selectors
            var subscriber: AnyCancellable?
    
            init(text: Binding<String>) {
                self.text = text
                super.init()
                subscriber = NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)
                    .sink() { [weak self] note in
                        print(self?.text.wrappedValue ?? "nil")
                        print("Publisher called -> " + note.description)
                }
    //            nc.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
            }
    
    
    //        @objc func keyboardWillShow(notification: Notification) {
    //            print("Selector called -> " + notification.description)
    //        }
    
            // Value should update in SwiftUI when return key is pressed to show that the data flows
            func textFieldShouldReturn(_ textField: UITextField) -> Bool {
                self.text.wrappedValue = textField.text ?? ""
                print(textField.text!)
                return true
            }
        }
    }
    

    【讨论】:

    • subscriber 的生命周期是多少?问题是在sink 处理程序中,我想使用self.text,但在初始化subscriber 属性时,Swift 不允许访问self
    • 只要 MyTextViewDelegate 存在,订阅者就会被保留,像观察者一样有效地工作。订阅者有一个“完成”订阅的概念,它有效地删除了订阅者,但在这种情况下不相关。我已经更新了上面的答案,将订阅者声明为 Optional,然后在 super.init() 之后的 init() 中将订阅者分配给它,以便 self 可用。这是有帮助还是我误解了?
    • 有道理!谢谢!
    • 关于这个的另一个问题 - 是否有必要实现 dismantleUIViewcancel() 所有 AnyCancellable 属性?
    • 不,你很好。 dismantleUIView具有默认实现,因此在大多数情况下您可能不需要实现自己的实现。 cancel() 仅在您想明确结束正在进行的订阅时才相关。当你的视图被释放时,它会被自动清理。
    猜你喜欢
    • 2021-10-22
    • 2021-06-13
    • 1970-01-01
    • 2020-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-08
    • 2022-12-05
    相关资源
    最近更新 更多