Fermez le clavier iOS en touchant n'importe où à l'aide de Swift


410

J'ai cherché partout mais je n'arrive pas à le trouver. Je sais comment supprimer le clavier en utilisant Objective-Cmais je ne sais pas comment faire cela en utilisant Swift? Est-ce que quelqu'un sait?


9
Comment ça se passe dans Objective-C? C'est normalement une conversion d'une syntaxe à l'autre, et rarement une question de méthodes / conventions différentes.
Craig Otis

5
Je n'ai pas creusé dans Swift, mais j'avais l'impression que l'API est la même…
coreyward

Vous voudrez peut-être vérifier cette réponse .
Ahmad F

Réponses:


1300
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)
}

Voici une autre façon d'effectuer cette tâche si vous comptez utiliser cette fonctionnalité en plusieurs 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)
    }
}

Maintenant, dans tout UIViewController, tout ce que vous avez à faire est d'appeler cette fonction:

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

Cette fonction est incluse en tant que fonction standard dans mon référentiel qui contient de nombreuses extensions Swift utiles comme celle-ci, consultez-la: https://github.com/goktugyil/EZSwiftExtensions


19
Depuis Swift 2 dans la première réponse, remplacez cette ligne-> let tap: UITapGestureRecognizer = UITapGestureRecognizer (cible: self, action: #selector (MyViewController.dismissKeyboard))
Sam Bellerose

2
il brise la séquence de tableviewcell sur un tableviewcontroller
Utku Dalmaz

11
C'est l'une des extensions les plus utiles que j'ai jamais rencontrées! Je vous remercie! La seule prudence que je voudrais apporter est que cela peut interférer didSelectRowAtIndexPath.
Clifton Labrum

47
Je viens de découvrir cette question et de mettre en œuvre cette méthode. Cette chose avec "didSelectRow" de tableView / UICollectionView sans appel m'a littéralement rendu fou. La solution est: simplement ajouter à votre poste: tap.cancelsTouchesInView = false. Cela l'a résolu pour moi au moins. J'espère que cela aide quelqu'un
Quantm

10
"Check out my repo" est le nouveau "Hears my new mixtape": P
Josh

118

Une réponse à votre question sur la façon de fermer le clavier dans Xcode 6.1 à l'aide de Swift ci-dessous:

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)
    }

}

( Source de cette information ).


6
Grand morceau de code, merci! touchesBegan était exactement ce que je cherchais :)
Lukasz Czerwinski

4
Cela n'a pas vraiment fonctionné pour moi. Si je tape sur la vue du contrôleur de vue, cela fonctionne. Si je tape sur un élément de contrôle dans la vue, le clavier ne se ferme pas.
user3731622

C'est la meilleure réponse que j'aie jamais utilisée jusqu'à présent! Cette réponse doit être marquée comme correcte. Merci mec!
wagng

C'est la meilleure solution que j'ai vue jusqu'à présent. Petite note: dans la nouvelle Swift, la signature de remplacement a un peu changé. Vous devez ajouter _ avant les touches: remplacer les touches de fonction Fungan (_ touches: définir <UITouch>, avec l'événement Event: UIEvent?)
Regis St-Gelais

1
Celui-ci devrait probablement être marqué comme correct. La réponse actuellement acceptée rend chaque bouton de la vue non réactif lorsque le clavier s'affiche.
Bartek Spitza

39

Swift 4 fonctionne

Créez l'extension comme ci-dessous et appelez hideKeyboardWhenTappedAround()dans votre contrôleur de vue de 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)
    }
}

La chose la plus importante à appeler dans votre Base View Controller afin que vous n'ayez pas besoin d'appeler tout le temps dans tous les contrôleurs de vue.


36

Tu peux appeler

resignFirstResponder()

sur n'importe quelle instance d'un répondeur UIR, comme un UITextField. Si vous l'appelez dans la vue qui provoque actuellement l'affichage du clavier, le clavier disparaîtra.


5
Dans une situation où vous ne connaissez pas exactement le premier répondant, resignFirstResponder () peut entraîner un tas de problèmes. La réponse d'Esq ci-dessous (en utilisant view.doneEditing ()) est beaucoup plus appropriée
shiser

1
Chaque fois que j'utilise resignFirstResponder sur mon textField, l'application se bloque. J'ai essayé tout ce à quoi je pouvais penser et j'ai cherché sur le Web une solution. Rien ne m'aide. Souhaitez-vous savoir pourquoi cela se produit?
AugustoQ

1
Comme l'a dit Shiser, ce n'est pas la meilleure solution. De plus, cela ne fonctionne pas dans toutes les situations.
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
    }

}

touchesBegan a travaillé pour moi pour mettre fin à l'édition de textfield et textview. Merci
Sanju

C'est ce que j'utilise, simple. Supprimez également les codes non liés pour vous concentrer sur la solution.
John Doe

19

pour Swift 3 c'est très simple

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

si vous voulez masquer le clavier en appuyant sur la touche RETOUR

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

mais dans le second cas, vous devrez également passer le délégué de tous les textFields au ViewController dans le Main.Storyboard


Je reçois unrecognized selector sent to instanceavec ce code.
Haring10

11

Swift 3: moyen le plus simple de supprimer le clavier:

  //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
    }

1
Je suis assez sûr que l'appel de view.endEditing (true) est plus simple en ce qu'il ne vous oblige pas à stocker une variable ou à supposer que vous n'avez qu'un seul champ de texte.
Glenn Howes

10

La réponse de Dash est correcte et préférée. Une approche plus "terre brûlée" est d'appeler view.endEditing(true). Cela provoque viewet toutes ses sous-vues resignFirstResponder. Si vous n'avez pas de référence à la vue que vous souhaitez ignorer, il s'agit d'une solution hacky mais efficace.

Notez que personnellement, je pense que vous devriez avoir une référence à la vue que vous aimeriez voir démissionner en tant que premier répondant. .endEditing(force: Bool)est une approche barbare; veuillez ne pas l'utiliser.


10

swift 5 deux lignes suffisent. Ajoutez à votre viewDidLoaddevrait fonctionner.

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

Si votre geste de toucher a bloqué d'autres touches, ajoutez cette ligne:

tapGesture.cancelsTouchesInView = false

Solution très simple et élégante :), devrait être la réponse ici.
Joseph Astrahan

9

Dans le storyboard:

  1. sélectionnez la TableView
  2. dans la partie droite, sélectionnez l'inspecteur d'attributs
  3. dans la section clavier - sélectionnez le mode de rejet souhaité

ne peut pas trouver cet article, où est-il et à quoi ressemble-t-il? Je suis dans l'inspecteur d'attributs d'un textField
Ethan Parker

Vous devez regarder le TableView et non TextField
zevij

9

Swift 3:

Extension avec Selectorcomme paramètre pour pouvoir faire des choses supplémentaires dans la fonction de rejet et cancelsTouchesInViewpour éviter la distorsion en touchant d'autres éléments de la vue.

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

Usage:

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

func dismissKeyboard() {
    view.endEditing(true)
    // do aditional stuff
}

9

Utilisez IQKeyboardmanager qui vous aidera à résoudre facilement .....

///////////////////////////////////////////

! [comment désactiver le clavier ..] [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)
  }
}

8

J'ai trouvé que la meilleure solution comprenait la réponse acceptée de @Esqarrouth, avec quelques ajustements:

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

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

La ligne tap.cancelsTouchesInView = falseétait critique: elle garantit que le UITapGestureRecognizern'empêche pas d'autres éléments de la vue de recevoir l'interaction de l'utilisateur.

La méthode a dismissKeyboard()été changée en légèrement moins élégante dismissKeyboardView(). C'est parce que dans la base de code assez ancienne de mon projet, il y avait de nombreuses fois où il dismissKeyboard()était déjà utilisé (j'imagine que ce n'est pas rare), provoquant des problèmes de compilation.

Ensuite, comme ci-dessus, ce comportement peut être activé dans des contrôleurs de vue individuels:

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

7

Si vous utilisez une vue de défilement, cela pourrait être beaucoup plus simple.

Sélectionnez simplement Dismiss interactivelydans le storyboard.


7

Dans Swift 4, ajoutez @objc:

Dans le viewDidLoad:

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

Une fonction:

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

7

Ajoutez cette extension à votre 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)
  }
}

6

Pour développer la réponse d'Esqarrouth , j'utilise toujours ce qui suit pour rejeter le clavier, surtout si la classe dont je supprime le clavier n'a pas de viewpropriété et / ou n'est pas une sous-classe deUIView .

UIApplication.shared.keyWindow?.endEditing(true)

Et, pour plus de commodité, l'extension suivante de la UIApplcationclasse:

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)
    }

}

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)
  }
}

5

En tant que programmeur débutant, cela peut être déroutant lorsque les gens produisent des réponses plus compétentes et inutiles ... Vous n'avez pas à faire les choses compliquées ci-dessus! ...

Voici l'option la plus simple ... Dans le cas où votre clavier apparaît en réponse au champ de texte - Dans votre fonction d'écran tactile, ajoutez simplement la fonction resignFirstResponder . Comme illustré ci-dessous - le clavier se fermera car le premier répondeur est libéré (en quittant la chaîne de répondeur) ...

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

5

J'ai utilisé IQKeyBoardManagerSwift pour le clavier. C'est facile a utiliser. il suffit d'ajouter le pod 'IQKeyboardManagerSwift'

Importez IQKeyboardManagerSwift et écrivez le code didFinishLaunchingWithOptionsdans AppDelegate.

///add this line 
IQKeyboardManager.shared.shouldResignOnTouchOutside = true
IQKeyboardManager.shared.enable = true

4

Cette doublure démissionne du clavier de tout (n'importe quel) UITextField dans une UIView

self.view.endEditing(true)

4

Une seule ligne de code dans la viewDidLoad()méthode:

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

4

En rapide vous pouvez utiliser

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

}

3

Pour Swift3

Enregistrer un identificateur d'événement dans viewDidLoad

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

nous devons ensuite ajouter le geste dans la vue dans le même viewDidLoad.

self.view.addGestureRecognizer(tap)

Ensuite, nous devons initialiser la méthode enregistrée

func hideKeyBoard(sender: UITapGestureRecognizer? = nil){
    view.endEditing(true)
}

1
Merci pour la réponse complète et avec des notes. C'est la seule solution qui a fonctionné pour moi.
zeeshan

3

Publication en tant que nouvelle réponse depuis que ma modification de la réponse de @ King-Wizard a été rejetée.

Faites de votre classe un délégué de UITextField et remplacez touchesBegan.

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)
    }

}

2

Vous pouvez également ajouter un outil de reconnaissance des mouvements tactiles pour démissionner du clavier. :RÉ

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")
}

2

Une autre possibilité consiste à simplement ajouter un gros bouton sans contenu se trouvant sous toutes les vues que vous pourriez avoir besoin de toucher. Donnez-lui une action nommée:

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

Le problème avec un identificateur de geste était pour moi, qu'il a également attrapé toutes les touches que je voulais recevoir par la tableViewCells.


2

Si vous avez d'autres vues qui devraient également être touchées, vous devez définir cancelsTouchesInView = false

Comme ça:

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

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

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

}

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

Essayez ça, ça marche


1

Lorsqu'il y a plusieurs champs de texte dans la vue

Pour suivre la recommandation de @ modocache d'éviter d'appeler view.endEditing(), vous pouvez garder une trace du champ de texte qui est devenu premier répondeur, mais qui est désordonné et sujet aux erreurs.

Une alternative consiste à appeler resignFirstResponder() tous les champs de texte dans le viewcontroller . Voici un exemple de création d'une collection de tous les champs de texte (qui dans mon cas était de toute façon nécessaire pour le code de validation):

@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]
}

Avec la collection disponible, il est simple d'itérer à travers chacun d'eux:

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

Alors maintenant, vous pouvez appeler dismissKeyboard()votre reconnaissance de gestes (ou là où cela vous convient). L'inconvénient est que vous devez conserver la liste des UITextFields lorsque vous ajoutez ou supprimez des champs.

Commentaires bienvenus. S'il y a un problème avec l'appel resignFirstResponder()de contrôles qui ne sont pas les premiers intervenants, ou s'il existe un moyen simple et garanti sans bug de suivre le premier répondant actuel, j'aimerais en entendre parler!

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.