Introducción: ¿por qué el teclado no se cierra solo?
\n¡Hola, colega desarrollador! Si alguna vez has escrito un formulario de inicio de sesión, una barra de búsqueda o un mensajero en iOS, seguramente te has encontrado con esta situación: el usuario ha ingresado texto, pero el teclado se queda obstinadamente en la pantalla. El botón "Listo" no se ha presionado, el usuario toca un espacio vacío, pero no sucede nada. Un clásico.
\n\nEste es uno de los temas más populares en Stack Overflow, donde la pregunta "Close iOS Keyboard by touching anywhere using Swift" ha acumulado miles de visitas. El problema no es que sea difícil de hacer. El problema es que los principiantes (y no solo ellos) a menudo eligen formas incorrectas o "sucias". Analicemos los 3 errores principales y luego veamos tres soluciones correctas y funcionales.
\n\nHoy hablamos de Swift y UIKit. Si usas SwiftUI, también échale un vistazo, los principios son similares.
\n\nError n.º 1: "Ponemos TapGesture en todo"
\nEl error más común es agregar un UITapGestureRecognizer a la UIView, pero olvidar desactivar cancelsTouchesInView. Como resultado, los botones y las tablas dejan de responder a los toques. El usuario toca el botón "Enviar", pero se activa el cierre del teclado, no el envío del formulario.
Ejemplo de código incorrecto:
\noverride func viewDidLoad() {\n super.viewDidLoad()\n let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))\n view.addGestureRecognizer(tap)\n}\n\n@objc func dismissKeyboard() {\n view.endEditing(true)\n}\n\nA primera vista, todo está bien. Pero en la práctica, si tienes una UITableView o un UIButton, sus toques pueden ser "tragados" por este gesto. Esto es especialmente notable cuando agregas dicho gesto a un scrollView.
Cómo solucionarlo:
\nAgrega la línea tap.cancelsTouchesInView = false. Esto permitirá que otros elementos de la interfaz reciban eventos táctiles.
let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))\ntap.cancelsTouchesInView = false\nview.addGestureRecognizer(tap)\n\nPero incluso esto no es una solución ideal si tienes una interfaz compleja.
\n\nError n.º 2: "Tocar un espacio vacío rompe la tabla"
\nEl segundo problema popular es la interacción incorrecta con UIScrollView o UITableView. Si agregas un UITapGestureRecognizer a la view que contiene una tabla, al tocar una celda puede activarse simultáneamente el gesto y el método didSelectRow. O, peor aún, el gesto interceptará el toque y la celda no se resaltará.
Solución: usa UIGestureRecognizerDelegate
\nImplementa el método gestureRecognizer(_:shouldReceive:) y verifica si el toque fue en un campo de texto o en otro elemento. Si el toque fue en un UITextField o UITextView, no bloquees el gesto.
extension ViewController: UIGestureRecognizerDelegate {\n func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {\n // No interceptamos toques si son en un campo de texto\n if touch.view is UITextField || touch.view is UITextView {\n return false\n }\n return true\n }\n}\n\nAhora el gesto solo se activará al tocar áreas vacías, y los campos de texto permanecerán interactivos.
\n\nError n.º 3: "Olvidamos el retorno del teclado"
\nMuchos desarrolladores implementan el cierre con un toque, pero olvidan el botón "Return" (Enter) del teclado. El usuario puede presionar "Listo" y esperar que el teclado se cierre. Si no se hace esto, obtendrás una mala experiencia de usuario (UX).
\n\nCómo solucionarlo:
\nSuscríbete al protocolo UITextFieldDelegate e implementa el método textFieldShouldReturn:
class View