Cierre el teclado iOS tocando cualquier lugar con Swift

409

He estado buscando todo esto, pero parece que no puedo encontrarlo. Sé cómo descartar el teclado usando Objective-Cpero no tengo idea de cómo hacerlo usando Swift. ¿Alguien sabe?

laguna
fuente
99
¿Cómo lo estás haciendo en Objective-C? Normalmente es una conversión de una sintaxis a otra, y rara vez se trata de diferentes métodos / convenciones.
Craig Otis
55
No he excavado en Swift, pero yo tenía la impresión de la API es el mismo ...
coreyward
Es posible que desee verificar esta respuesta .
Ahmad F

Respuestas:

1299
override func viewDidLoad() {
    super.viewDidLoad()

    //Looks for single or multiple taps. 
    let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "dismissKeyboard")

    //Uncomment the line below if you want the tap not not interfere and cancel other interactions.
    //tap.cancelsTouchesInView = false 

    view.addGestureRecognizer(tap)
}

//Calls this function when the tap is recognized.
@objc func dismissKeyboard() {
    //Causes the view (or one of its embedded text fields) to resign the first responder status.
    view.endEditing(true)
}

Aquí hay otra forma de hacer esta tarea si va a utilizar esta funcionalidad en múltiples UIViewControllers:

// Put this piece of code anywhere you like
extension UIViewController {
    func hideKeyboardWhenTappedAround() {
        let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
        tap.cancelsTouchesInView = false            
        view.addGestureRecognizer(tap)
    }

    @objc func dismissKeyboard() {
        view.endEditing(true)
    }
}

Ahora en cada UIViewController, todo lo que tienes que hacer es llamar a esta función:

override func viewDidLoad() {
    super.viewDidLoad()
    self.hideKeyboardWhenTappedAround() 
}

Esta función se incluye como una función estándar en mi repositorio que contiene muchas Extensiones Swift útiles como esta, échale un vistazo: https://github.com/goktugyil/EZSwiftExtensions

Esqarrouth
fuente
19
Desde Swift 2 en la primera respuesta, reemplace esta línea-> deje tocar: UITapGestureRecognizer = UITapGestureRecognizer (target: self, action: #selector (MyViewController.dismissKeyboard))
Sam Bellerose
2
rompe la segue de tableviewcell en un controlador de tableview
Utku Dalmaz
11
¡Esta es una de las extensiones más útiles que he encontrado! ¡Gracias! La única advertencia que extendería es que esto puede interferir didSelectRowAtIndexPath.
Clifton Labrum
47
Acabo de descubrir esta pregunta e implementé ese método. Esa cosa con "didSelectRow" de tableView / UICollectionView no llamando literalmente me volvió loco. La solución es: Basta con añadir esto a su extensión: tap.cancelsTouchesInView = false. Eso me resolvió al menos. Esperamos que esto ayude a alguien
Quantm
10
"Mira mi repositorio" es el nuevo "Escucha mi nuevo mixtape": P
Josh
118

Una respuesta a su pregunta sobre cómo descartar el teclado en Xcode 6.1 usando Swift a continuación:

import UIKit

class ItemViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet var textFieldItemName: UITextField!

    @IBOutlet var textFieldQt: UITextField!

    @IBOutlet var textFieldMoreInfo: UITextField!


    override func viewDidLoad() {
        super.viewDidLoad()

        textFieldItemName.delegate = self
        textFieldQt.delegate = self
        textFieldMoreInfo.delegate = self
    }

                       ...

    /**
     * Called when 'return' key pressed. return NO to ignore.
     */
    func textFieldShouldReturn(textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }


   /**
    * Called when the user click on the view (outside the UITextField).
    */
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        self.view.endEditing(true)
    }

}

( Fuente de esta información ).

Rey Mago
fuente
66
Gran código, gracias! touchesBegan era exactamente lo que estaba buscando :)
Lukasz Czerwinski
44
Esto no funcionó para mí. Si toco en la vista del controlador de vista, funciona. Si toco un elemento de control en la vista, el teclado no se descarta.
user3731622
¡Esta es la mejor respuesta que he usado hasta ahora! Esta respuesta debe marcarse como correcta. ¡Gracias hombre!
wagng
Esta es la mejor solución que he visto hasta ahora. Pequeña nota: en el nuevo Swift, la firma de anulación cambió un poco. Es necesario añadir _ antes de toques: anulación func touchesBegan (_ toques: Set <UITouch>, evento withEvent:? UIEvent)
Regis St-Gelais
1
Este probablemente debería estar marcado como correcto. La respuesta aceptada actual hace que cada botón de la vista no responda cuando se muestra el teclado.
Bartek Spitza
39

Swift 4 trabajando

Cree una extensión como la siguiente y llame hideKeyboardWhenTappedAround()a su controlador de vista Base.

//
//  UIViewController+Extension.swift
//  Project Name
//
//  Created by ABC on 2/3/18.
//  Copyright © 2018 ABC. All rights reserved.
//

import UIKit

extension UIViewController {
    func hideKeyboardWhenTappedAround() {
        let tapGesture = UITapGestureRecognizer(target: self, 
                         action: #selector(hideKeyboard))
        view.addGestureRecognizer(tapGesture)
    }

    @objc func hideKeyboard() {
        view.endEditing(true)
    }
}

Lo más importante para llamar en su controlador de vista base para que no tenga que llamar todo el tiempo en todos los controladores de vista.

Fahim Parkar
fuente
36

Puedes llamar

resignFirstResponder()

en cualquier instancia de un UIResponder, como un UITextField. Si lo llama en la vista que está causando que se muestre el teclado, el teclado se cerrará.

Guión
fuente
55
En una situación en la que no conoce exactamente el primer respondedor, resignFirstResponder () puede ocasionar muchos problemas. La respuesta de Esq a continuación (usando view.doneEditing ()) es mucho más apropiada
shiser
1
Cada vez que uso resignFirstResponder en mi textField, la aplicación se bloquea. Intenté todo lo que se me ocurrió y busqué una solución en la web. Nada me ayuda. ¿Sabrías por qué sucede eso?
AugustoQ
1
Como dijo Shiser, esta no es la mejor solución. Además, no funciona en todas las situaciones.
Alix
21
//Simple exercise to demonstrate, assuming the view controller has a //Textfield, Button and a Label. And that the label should display the //userinputs when button clicked. And if you want the keyboard to disappear //when clicken anywhere on the screen + upon clicking Return key in the //keyboard. Dont forget to add "UITextFieldDelegate" and 
//"self.userInput.delegate = self" as below

import UIKit

class ViewController: UIViewController,UITextFieldDelegate {

    @IBOutlet weak var userInput: UITextField!
    @IBAction func transferBtn(sender: AnyObject) {
                display.text = userInput.text

    }
    @IBOutlet weak var display: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

//This is important for the textFieldShouldReturn function, conforming to textfieldDelegate and setting it to self
        self.userInput.delegate = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

//This is for the keyboard to GO AWAYY !! when user clicks anywhere on the view
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        self.view.endEditing(true)
    }


//This is for the keyboard to GO AWAYY !! when user clicks "Return" key  on the keyboard

    func textFieldShouldReturn(textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }

}
Naishta
fuente
touchesBegan trabajó para mí para finalizar la edición del campo de texto y la vista de texto. Gracias
Sanju
Esto es lo que uso, simple. Elimine también los códigos no relacionados para centrarse en la solución.
John Doe
19

para Swift 3 es muy simple

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    self.view.endEditing(true)
}

si quieres ocultar el teclado al presionar la tecla RETURN

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    textField.resignFirstResponder()
    return true
}

pero en el segundo caso, también deberá pasar delegado de todos los campos de texto al ViewController en el Tablero principal.

Yerbol
fuente
Me sale unrecognized selector sent to instancecon este código.
Haring10
11

Swift 3: la forma más fácil de descartar el teclado:

  //Dismiss keyboard method
    func keyboardDismiss() {
        textField.resignFirstResponder()
    }

    //ADD Gesture Recignizer to Dismiss keyboard then view tapped
    @IBAction func viewTapped(_ sender: AnyObject) {
        keyboardDismiss()
    }

    //Dismiss keyboard using Return Key (Done) Button
    //Do not forgot to add protocol UITextFieldDelegate 
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        keyboardDismiss()

        return true
    }
NikaE
fuente
1
Estoy bastante seguro de que la llamada view.endEditing (true) es más simple ya que no requiere que almacene una variable o suponga que solo tiene un campo de texto.
Glenn Howes
10

La respuesta de Dash es correcta y preferida. Un enfoque más "tierra quemada" es llamar view.endEditing(true). Esto provoca viewy todas sus subvistas a resignFirstResponder. Si no tiene una referencia a la vista que le gustaría descartar, esta es una solución hacky pero efectiva.

Tenga en cuenta que personalmente creo que debería tener una referencia a la vista en la que desea renunciar al primer respondedor. .endEditing(force: Bool)es un enfoque bárbaro; por favor no lo uses

modocache
fuente
10

Swift 5 solo dos líneas es suficiente. Añadir a su viewDidLoaddebería funcionar.

 let tapGesture = UITapGestureRecognizer(target: view, action: #selector(UIView.endEditing))
 view.addGestureRecognizer(tapGesture)

Si su gesto de toque bloqueó otros toques, agregue esta línea:

tapGesture.cancelsTouchesInView = false
William Hu
fuente
Solución muy simple y elegante :), debería ser la respuesta aquí.
Joseph Astrahan
9

En storyboard:

  1. seleccione el TableView
  2. desde el lado derecho, seleccione el inspector de atributos
  3. en la sección del teclado: seleccione el modo de descarte que desee
zevij
fuente
no puedo encontrar ese artículo, ¿dónde está y cómo se ve? Estoy en el inspector de atributos de un campo de texto
Ethan Parker
Debe mirar TableView, no TextField
zevij
9

Swift 3:

Extensión con Selectorcomo parámetro para poder hacer cosas adicionales en la función de descarte y cancelsTouchesInViewevitar distorsiones con toques en otros elementos de la vista.

extension UIViewController {
    func hideKeyboardOnTap(_ selector: Selector) {
        let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: selector)
        tap.cancelsTouchesInView = false
        view.addGestureRecognizer(tap)
    }
}

Uso:

override func viewDidLoad() {
    super.viewDidLoad()
    self.hideKeyboardOnTap(#selector(self.dismissKeyboard))
}

func dismissKeyboard() {
    view.endEditing(true)
    // do aditional stuff
}
David Seek
fuente
9

Utilice IQKeyboardmanager que lo ayudará a resolver fácilmente .....

/////////////////////////////////////////.

! [cómo deshabilitar el teclado ..] [1]

import UIKit

class ViewController: UIViewController,UITextFieldDelegate {

   @IBOutlet weak var username: UITextField!
   @IBOutlet weak var password: UITextField!

   override func viewDidLoad() {
      super.viewDidLoad() 
      username.delegate = self
      password.delegate = self
      // Do any additional setup after loading the view, typically from a nib.
   }

   override func didReceiveMemoryWarning() {
      super.didReceiveMemoryWarning()
      // Dispose of any resources that can be recreated.
   }

   func textFieldShouldReturn(textField: UITextField!) -> Bool // called when   'return' key pressed. return NO to ignore.
   {
      textField.resignFirstResponder()
      return true;
   }

   override func touchesBegan(_: Set<UITouch>, with: UIEvent?) {
     username.resignFirstResponder()
     password.resignFirstResponder()
     self.view.endEditing(true)
  }
}
Hardik Bar
fuente
8

Encontré que la mejor solución incluía la respuesta aceptada de @Esqarrouth, con algunos ajustes:

extension UIViewController {
    func hideKeyboardWhenTappedAround() {
        let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "dismissKeyboardView")
        tap.cancelsTouchesInView = false
        view.addGestureRecognizer(tap)
    }

    func dismissKeyboardView() {
        view.endEditing(true)
    }
}

La línea tap.cancelsTouchesInView = falsefue crítica: asegura que UITapGestureRecognizerno evita que otros elementos en la vista reciban interacción del usuario.

El método dismissKeyboard()fue cambiado a un poco menos elegante dismissKeyboardView(). Esto se debe a que en la base de código bastante antigua de mi proyecto, hubo numerosas ocasiones en que dismissKeyboard()ya se usaba (imagino que esto no es infrecuente), causando problemas de compilación.

Luego, como se indicó anteriormente, este comportamiento se puede habilitar en controladores de vista individuales:

override func viewDidLoad() {
    super.viewDidLoad()
    self.hideKeyboardWhenTappedAround() 
}
Luke Harries
fuente
7

Si usa una vista de desplazamiento, podría ser mucho más simple.

Simplemente seleccione Dismiss interactivelyen el guión gráfico.

JIE WANG
fuente
7

En Swift 4, agregue @objc:

En la viewDidLoad:

let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.dismissKeyboard))
view.addGestureRecognizer(tap)

Función:

@objc func dismissKeyboard() {
  view.endEditing(true)
}
usuario3856297
fuente
7

Agregue esta extensión a su ViewController:

  extension UIViewController {
// Ends editing view when touches to view 
  open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesBegan(touches, with: event)
    self.view.endEditing(true)
  }
}
Jarvis el vengador
fuente
6

Para ampliar la respuesta de Esqarrouth , siempre uso lo siguiente para descartar el teclado, especialmente si la clase de la que descarto el teclado no tiene una viewpropiedad y / o no es una subclase deUIView .

UIApplication.shared.keyWindow?.endEditing(true)

Y, por conveniencia, la siguiente extensión de la UIApplcationclase:

extension UIApplication {

    /// Dismisses the keyboard from the key window of the
    /// shared application instance.
    ///
    /// - Parameters:
    ///     - force: specify `true` to force first responder to resign.
    open class func endEditing(_ force: Bool = false) {
        shared.endEditing(force)
    }

    /// Dismisses the keyboard from the key window of this 
    /// application instance.
    ///
    /// - Parameters:
    ///     - force: specify `true` to force first responder to resign.
    open func endEditing(_ force: Bool = false) {
        keyWindow?.endEditing(force)
    }

}
NoodleOfDeath
fuente
5
  import UIKit

  class ItemViewController: UIViewController, UITextFieldDelegate {

  @IBOutlet weak var nameTextField: UITextField!

    override func viewDidLoad() {
           super.viewDidLoad()
           self.nameTextField.delegate = self
     }

    // Called when 'return' key pressed. return NO to ignore.

    func textFieldShouldReturn(textField: UITextField) -> Bool {

            textField.resignFirstResponder()
             return true
     }

 // Called when the user click on the view (outside the UITextField).

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)    {
      self.view.endEditing(true)
  }
}
Chaudhary prasante
fuente
5

Como programador novato, puede ser confuso cuando las personas producen respuestas más hábiles e innecesarias ... ¡No tiene que hacer nada de lo complicado que se muestra arriba! ...

Aquí está la opción más simple ... En el caso de que su teclado aparezca en respuesta al campo de texto - Dentro de la función de su pantalla táctil simplemente agregue la función resignFirstResponder . Como se muestra a continuación, el teclado se cerrará porque se libera el primer respondedor (saliendo de la cadena de respuesta) ...

override func touchesBegan(_: Set<UITouch>, with: UIEvent?){
    MyTextField.resignFirstResponder()
}
Cielo Rojo
fuente
5

He usado IQKeyBoardManagerSwift para teclado. Es fácil de usar. simplemente agregue el pod 'IQKeyboardManagerSwift'

Importe IQKeyboardManagerSwift y escriba el código didFinishLaunchingWithOptionsen AppDelegate.

///add this line 
IQKeyboardManager.shared.shouldResignOnTouchOutside = true
IQKeyboardManager.shared.enable = true
Sukhwinder Singh
fuente
4

Este revestimiento renuncia al teclado de todos (cualquiera) el UITextField en una UIView

self.view.endEditing(true)
Codetard
fuente
4

Solo una línea de código en el viewDidLoad()método:

view.addGestureRecognizer(UITapGestureRecognizer(target: view, action: #selector(UIView.endEditing(_:))))
Artem
fuente
4

En Swift puedes usar

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesBegan(touches, with: event)
    view.endEditing(true)

}
bernard rayoso
fuente
3

Para Swift3

Registre un reconocedor de eventos en viewDidLoad

let tap = UITapGestureRecognizer(target: self, action: #selector(hideKeyBoard))

entonces necesitamos agregar el gesto a la vista en la misma vistaDidLoad.

self.view.addGestureRecognizer(tap)

Entonces necesitamos inicializar el método registrado

func hideKeyBoard(sender: UITapGestureRecognizer? = nil){
    view.endEditing(true)
}
Sandu
fuente
1
Gracias por la respuesta completa y con notas. Esta es la única solución que funcionó para mí.
zeeshan
3

Publicando como una nueva respuesta ya que mi edición de la respuesta de @ King-Wizard fue rechazada.

Convierta a su clase en un delegado del UITextField y anule los toques de inicio.

Swift 4

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet var textField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        textField.delegate = self
    }

    //Called when 'return' key is pressed. Return false to keep the keyboard visible.
    func textFieldShouldReturn(textField: UITextField) -> Bool {
        return true
    }

    // Called when the user clicks on the view (outside of UITextField).
    override func touchesBegan(touches: Set<UITouch>, with event: UIEvent?) {
        self.view.endEditing(true)
    }

}
Viktor Seč
fuente
2

También puede agregar un reconocedor de gestos de toque para renunciar al teclado. :RE

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    let recognizer = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
    backgroundView.addGestureRecognizer(recognizer)
}
    func handleTap(recognizer: UITapGestureRecognizer) {
    textField.resignFirstResponder()
    textFieldtwo.resignFirstResponder()
    textFieldthree.resignFirstResponder()

    println("tappped")
}
Codetard
fuente
2

Otra posibilidad es simplemente agregar un botón grande sin contenido que se encuentre debajo de todas las vistas que deba tocar. Dale una acción llamada:

@IBAction func dismissKeyboardButton(sender: AnyObject) {
    view.endEditing(true)
}

El problema con un reconocedor de gestos fue para mí, que también captó todos los toques que quería recibir por parte de tableViewCells.

Timm Kent
fuente
2

Si tiene otras vistas que también deberían recibir el toque, debe configurar cancelsTouchesInView = false

Me gusta esto:

let elsewhereTap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
    elsewhereTap.cancelsTouchesInView = false
    self.view.addGestureRecognizer(elsewhereTap)
ph1lb4
fuente
2
override func viewDidLoad() {
        super.viewDidLoad()

self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tap)))

}

func tap(sender: UITapGestureRecognizer){
        print("tapped")
        view.endEditing(true)
}

Intenta esto, está funcionando

Ramprasath Selvam
fuente
1

Cuando hay más de un campo de texto en la vista

Para seguir @ recomendación de modocache a llamar Noview.endEditing() , puede realizar un seguimiento del campo de texto que se convirtió en el primer respondedor, pero eso es desordenado y propenso a errores.

Una alternativa es llamar resignFirstResponder() a todos los campos de texto en el controlador de vista . Aquí hay un ejemplo de cómo crear una colección de todos los campos de texto (que en mi caso era necesario para el código de validación de todos modos):

@IBOutlet weak var firstName: UITextField!
@IBOutlet weak var lastName: UITextField!
@IBOutlet weak var email: UITextField!

var allTextFields: Array<UITextField>!  // Forced unwrapping so it must be initialized in viewDidLoad
override func viewDidLoad()
{
    super.viewDidLoad()
    self.allTextFields = [self.firstName, self.lastName, self.email]
}

Con la colección disponible, es muy sencillo iterar a través de todos ellos:

private func dismissKeyboard()
{
    for textField in allTextFields
    {
        textField.resignFirstResponder()
    }
}

Así que ahora puede llamar dismissKeyboard()a su gestor de reconocimiento (o donde sea apropiado para usted). El inconveniente es que debe mantener la lista de UITextFields cuando agrega o elimina campos.

Comentarios bienvenidos Si hay un problema con la invocación resignFirstResponder()de controles que no responden primero, o si hay una manera fácil y garantizada sin errores de rastrear al primer respondedor actual, ¡me encantaría saberlo!

Roca
fuente