Por qué se llama al observer onKeyboardDisplayed antes que textViewDidBeginEditing

Dec 23 2020

Mi aplicación es rápida. Cuando edito un UITextField, a veces el teclado oculta el campo. Entonces uso el delegado textFieldDidBeginEditing para establecer un "activeTextField" (y textFieldDidEndEditing para restablecerlo a cero). Luego, en viewDidLoad agrego un observador vinculado a una función onKeyboardDisplayed donde pruebo el valor de "activeTextField" para poder deslizar la pantalla hacia arriba si es necesario. Y funciona bien :)

La mala noticia es que traté de hacer lo mismo para un UITextView, usando delegado textViewDidBeginEditing para establecer un "activeTextView". Pero a diferencia de UITextField, el delegado se llama después de onKeyboardDisplayed, por lo que el teclado aún oculta mi UITextView.

NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardDisplayed(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)

@objc func onKeyboardDisplayed(notification: Notification) {
    guard let keyboardRect = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else {
        return
    }
    var visibleRect : CGRect = self.view.frame
    visibleRect.size.height -= keyboardRect.height
    if (activeTextField != nil) {
        // Get y position of active textField bottom.
        let textFieldBottomPosition = activeTextField!.convert(CGPoint.zero, to: nil).y + activeTextField!.frame.height
        if(textFieldBottomPosition > visibleRect.size.height) {
            // swipe up
            view.frame.origin.y = (visibleRect.size.height - textFieldBottomPosition - 6)
        }
    }
    if (activeTextView != nil) {
        // Get y position of active textView bottom.
        let textViewBottomPosition = activeTextView!.convert(CGPoint.zero, to: nil).y + activeTextView!.frame.height
        if(textViewBottomPosition > visibleRect.size.height) {
            // swipe up
            view.frame.origin.y = (visibleRect.size.height - textViewBottomPosition - 6)
        }
    }
}

¿Conoces una forma de solucionarlo?

Respuestas

2 syntiz Dec 23 2020 at 20:36

Finalmente encontré una solución aquí: eventos de teclado llamados antes de eventos delegados de UITextView

Cambié el teclado WillShowNotification

NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardDisplayed(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)

por keyboardDidShowNotification

NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardDisplayed(notification:)), name: UIResponder.keyboardDidShowNotification, object: nil)

Y ahora funciona bien: mi función onKeyboardDisplayed se llama después del delegado textViewDidBeginEditing

1 LucaSfragara Dec 23 2020 at 18:54

La forma estándar de lidiar con la aparición del teclado es esta

En su ViewController:

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillShow), name: UIControl.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillHide), name: UIControl.keyboardWillHideNotification, object: nil)
 }

 @objc private func handleKeyboardWillShow(notification: NSNotification){
    
    guard let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else{
        return
    }
    self.view.frame.origin.y -= keyboardSize.height
}

@objc private func handleKeyboardWillHide(notification: NSNotification){
    self.view.frame.origin.y = 0
}

Esto mueve el marco de vista hacia arriba y hacia abajo de acuerdo con la altura del teclado. Si entiendo correctamente su pregunta, creo que esto puede ayudarlo