web-dev-qa-db-fra.com

iOS - Fermer le clavier lorsque vous touchez en dehors de UITextField

Je me demande comment faire disparaître le clavier lorsque l'utilisateur touche en dehors d'un UITextField.

441
jonepatr

Vous devez ajouter un UITapGestureRecogniser et l'affecter à la vue, puis appeler le premier répondant démissionnaire sur le UITextField de son sélecteur.

Le code:

dans viewDidLoad

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];

[self.view addGestureRecognizer:tap];

Dans licenciement :)

-(void)dismissKeyboard 
{
    [aTextField resignFirstResponder];
}

(Où aTextField est le champ de texte responsable du clavier)

Swift la version ressemble à ça

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

Pour licenciement

func dismissKeyboard (_ sender: UITapGestureRecognizer) {
    aTextField.resignFirstResponder()
}
738
Jensen2k

J'ai écrasé quelques réponses.

Utilisez un ivar initialisé pendant viewDidLoad:

UIGestureRecognizer *tapper;

- (void)viewDidLoad
{
    [super viewDidLoad];
    tapper = [[UITapGestureRecognizer alloc]
                initWithTarget:self action:@selector(handleSingleTap:)];
    tapper.cancelsTouchesInView = NO;
    [self.view addGestureRecognizer:tapper];
}

Ignorer ce qui est en train d'être édité:

- (void)handleSingleTap:(UITapGestureRecognizer *) sender
{
    [self.view endEditing:YES];
}
171
drewish

Cochez ceci, ce serait le moyen le plus simple de le faire,

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
      [self.view endEditing:YES];// this will do the trick
}

Ou

Cette bibliothèque gérera notamment le défilement automatique de la barre de défilement, la touche Tap pour masquer le clavier, etc.

https://github.com/michaeltyson/TPKeyboardAvoiding

101
Prasad De Zoysa

Je vois que certaines personnes ont des problèmes avec la méthode UITapGestureRecognizer. Le moyen le plus simple d’effectuer cette fonctionnalité tout en conservant intact le comportement de mon bouton actuel consiste à ajouter une seule ligne à la réponse de @ Jensen2k:

[tap setCancelsTouchesInView:NO];

Cela a permis à mes boutons existants de continuer à fonctionner sans utiliser la méthode de @Dmitry Sitnikov.

Lisez à ce sujet property ici (recherchez CancelsTouchesInView): Référence de la classe UIGestureRecognizer

Je ne suis pas sûr de savoir comment cela fonctionnerait avec les barres de défilement, car je vois que certains avaient des problèmes, mais j'espère que quelqu'un d'autre rencontrera le même scénario que moi.

86
Qiao Yi

Il est préférable de faire de votre UIView une instance de UIControl (dans le générateur d'interface), puis de connecter leur événement TouchUpInside à la méthode dismissKeyboard. Cette méthode IBAction ressemblera à ceci:

- (IBAction)dismissKeyboard:(id)sender {
    [aTextBox resignFirstResponder];
}
55
Dmitry Sitnikov

Version rapide, cela fonctionne en combinaison avec d'autres éléments (comme un UIButton ou un autre UITextField):

override func viewDidLoad() {
    super.viewDidLoad()

    let tapper = UITapGestureRecognizer(target: self, action:#selector(endEditing))
    tapper.cancelsTouchesInView = false
    view.addGestureRecognizer(tapper)
}
28
Rob

Swift 4

Configurez votre UIViewController avec cette méthode d’extension une fois, par exemple, dans viewDidLoad:

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

et le clavier sera ignoré même en tapant sur la touche NavigationBar.

import UIKit
extension UIViewController {
    /// Call this once to dismiss open keyboards by tapping anywhere in the view controller
    func setupHideKeyboardOnTap() {
        self.view.addGestureRecognizer(self.endEditingRecognizer())
        self.navigationController?.navigationBar.addGestureRecognizer(self.endEditingRecognizer())
    }

    /// Dismisses the keyboard from self.view
    private func endEditingRecognizer() -> UIGestureRecognizer {
        let tap = UITapGestureRecognizer(target: self.view, action: #selector(self.view.endEditing(_:)))
        tap.cancelsTouchesInView = false
        return tap
    }
}
21
FBente

Que diriez-vous de cela: je sais que c'est un ancien post. Cela pourrait aider quelqu'un :)

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {  
    NSArray *subviews = [self.view subviews];
    for (id objects in subviews) {
        if ([objects isKindOfClass:[UITextField class]]) {
            UITextField *theTextField = objects;
            if ([objects isFirstResponder]) {
                [theTextField resignFirstResponder];
            }
        } 
    }
}
17
Mr H

C'est une bonne solution générique:

Objectif c:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.view endEditing:YES];    
}

Rapide:

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
    self.view.endEditing(true)
}

Basé sur la solution @icodebuster: https://stackoverflow.com/a/18756253/417652

14
eduludi

Je pense que le moyen le plus simple (et le meilleur) de procéder consiste à sous-classer votre vue globale et à utiliser la méthode hitTest:withEvent pour écouter tout contact. Les touches du clavier n'étant pas enregistrées, hitTest: withEvent n'est appelé que lorsque vous touchez/défilez/balayez/pincez ... ailleurs, puis appelez [self endEditing:YES].

C'est mieux que d'utiliser touchesBegan parce que touchesBegan ne sont pas appelés si vous cliquez sur un bouton en haut de la vue. C'est mieux que UITapGestureRecognizer qui ne reconnaît pas un geste de défilement par exemple. C'est également mieux que d'utiliser un écran sombre, car dans une interface utilisateur complexe et dynamique, vous ne pouvez pas placer l'écran sombre partout. De plus, il ne bloque pas d'autres actions, vous n'avez pas besoin d'appuyer deux fois pour sélectionner un bouton extérieur (comme dans le cas d'un UIPopover).

En outre, il vaut mieux appeler [textField resignFirstResponder], car vous pouvez avoir plusieurs champs de texte à l'écran, donc cela fonctionne pour tous.

10
Enzo Tran

Swift 4 oneliner

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

Vous pouvez le faire en utilisant le Storyboard dans XCode 6 et supérieur:


Créer l'action pour cacher le clavier

Ajoutez ceci au fichier d’en-tête de la classe utilisée par votre ViewController:

@interface TimeDelayViewController : UIViewController <UITextFieldDelegate>

- (IBAction)dissmissKeyboardOnTap:(id)sender;

@end

Ajoutez ensuite ceci au fichier d'implémentation du même ViewController:

- (IBAction)dissmissKeyboardOnTap:(id)sender{
    [[self view]endEditing:YES];
}

Ce sera désormais l'une des 'Actions reçues' pour votre scène de scénario (c'est-à-dire ViewController):

enter image description here


Relier l'action à l'événement utilisateur

Vous devez maintenant associer cette action au geste de l'utilisateur consistant à toucher le clavier.

Important - Vous devez convertir le 'UIView' contenu dans votre storyboard en UIControl afin qu'il puisse recevoir des événements. Sélectionnez la vue dans votre hiérarchie de scènes de contrôleur de vue:

enter image description here

... et change de classe:

enter image description here

À présent, faites glisser le cercle situé à côté de "l'action reçue" pour votre scène, sur une partie "vide" de votre scène (vous faites en fait glisser l'action "reçue" vers UIControl). Une sélection d'événements que vous pouvez associer à votre action vous sera présentée:

enter image description here

Sélectionnez l'option "Retouche à l'intérieur". Vous avez maintenant associé l'IBAction que vous avez créée à une action utilisateur consistant à toucher le clavier. Lorsque l'utilisateur appuie sur le clavier, celui-ci est maintenant masqué.

(REMARQUE: pour associer l'action à l'événement, vous pouvez également faire glisser l'action reçue directement sur UIControl dans la hiérarchie de vos contrôleurs de vue. Il est affiché sous la forme "Control" dans la hiérarchie.)

6
Chris Halcrow

Ce doit être le moyen le plus simple de masquer votre clavier en touchant à l'extérieur:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.view endEditing:YES];    
}

(de Comment supprimer un clavier lorsque l'utilisateur appuie sur une autre zone en dehors de textfield? )

6
KoreanXcodeWorker

Si la vue est incorporée dans un UIScrollView, vous pouvez utiliser les éléments suivants:

tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;

Le premier animera l’écran de désactivation du clavier lors du défilement de la vue du tableau et le second masquera le clavier comme l’application stock Messages.

Notez que ceux-ci sont disponibles sur iOS 7.0 ou une version ultérieure.

5
Joe Masilotti

Si je comprends bien, vous voulez quitter le clavier en tapant sur le côté extérieur de textfield mais vous n'avez pas de référence de votre textfield.

Essaye ça;

  • Prenez global textField, appelons-le reftextField
  • Maintenant, dans textFieldDidBeginEditing, définissez le champ de texte référencé sur

    - (void) textFieldDidBeginEditing:(UITextField *)textField{
        reftextField = textField;
    }
    
  • Maintenant, vous pouvez utiliser avec bonheur n'importe quelle horloge à boutons (ajouter un bouton transparent pour commencer l'édition recommandée)

    - (void)dismissKeyboard {
          [reftextField resignFirstResponder];
    }
    
  • Ou pour le bouton de démission fait, essayez ceci.

    //for resigning on done button    
    - (BOOL) textFieldShouldReturn:(UITextField *)textField{
        [textField resignFirstResponder];
        return YES;
    }
    
5
rptwsthi

Version rapide de la réponse de @ Jensen2k:

let gestureRecognizer : UITapGestureRecognizer = UITapGestureRecognizer.init(target: self, action: "dismissKeyboard")
self.view.addGestureRecognizer(gestureRecognizer)

func dismissKeyboard() {
    aTextField.resignFirstResponder()
}

Bon mot

self.view.addTapGesture(UITapGestureRecognizer.init(target: self, action: "endEditing:"))
3
Syed Asad Ali

Juste pour ajouter à la liste ici ma version de la façon de supprimer un clavier sans contact.

viewDidLoad:

UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
[self.view addGestureRecognizer:singleTap];

Nulle part:

-(void)handleSingleTap:(UITapGestureRecognizer *)sender{
    [textFieldName resignFirstResponder];
    puts("Dismissed the keyboard");
}
3
John Riselvato

Beaucoup de bonnes réponses ici sur l'utilisation de UITapGestureRecognizer-- toutes qui cassent le bouton clear (X) de UITextField. La solution consiste à supprimer la reconnaissance de geste via son délégué:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    BOOL touchViewIsButton = [touch.view isKindOfClass:[UIButton class]];
    BOOL touchSuperviewIsTextField = [[touch.view superview] isKindOfClass:[UITextField class]];
    return !(touchViewIsButton && touchSuperviewIsTextField);
}

Ce n'est pas la solution la plus robuste, mais cela fonctionne pour moi.

3
skedastik

Vous pouvez créer une catégorie pour UiView et remplacer le meathod de toucheBegan comme suit.

Cela fonctionne très bien pour moi. Et c'est une solution centralisée pour ce problème.

#import "UIView+Keyboard.h"
@implementation UIView(Keyboard)

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.window endEditing:true];
    [super touchesBegan:touches withEvent:event];
}
@end
3
Hiren

L’un des moyens les plus simples et les plus simples consiste à ajouter ce code à votre viewDidLoad

[self.view addGestureRecognizer:[[UITapGestureRecognizer alloc]
                                     initWithTarget:self.view
                                     action:@selector(endEditing:)]];
2
Sudhin Davis

J'ai essayé beaucoup de réponses ici et je n'ai pas eu de chance. Mon outil de reconnaissance des gestes entraînait toujours mon UIButtons à ne pas répondre lorsqu'il était tapé, même lorsque je définissais la propriété cancelsTouchesInView du dispositif de reconnaissance des gestes sur NO.

C'est ce qui a finalement résolu le problème:

Avoir un ivar:

UITapGestureRecognizer *_keyboardDismissGestureRecognizer;

Lorsqu'un texte commence à être modifié, définissez la reconnaissance de geste:

- (void) textFieldDidBeginEditing:(UITextField *)textField
{
    if(_keyboardDismissGestureRecognizer == nil)
    {
        _keyboardDismissGestureRecognizer = [[[UITapGestureRecognizer alloc]
                                       initWithTarget:self
                                       action:@selector(dismissKeyboard)] autorelease];
        _keyboardDismissGestureRecognizer.cancelsTouchesInView = NO;

        [self.view addGestureRecognizer:_keyboardDismissGestureRecognizer];
    }
}

Ensuite, l’astuce consiste à configurer la méthode dismissKeyboard:

- (void) dismissKeyboard
{
    [self performSelector:@selector(dismissKeyboardSelector) withObject:nil afterDelay:0.01];
}

- (void) dismissKeyboardSelector
{
    [self.view endEditing:YES];

    [self.view removeGestureRecognizer:_keyboardDismissGestureRecognizer];
    _keyboardDismissGestureRecognizer = nil;
}

Je suppose qu'il y a simplement quelque chose à faire pour obtenir l'exécution dismissKeyboardSelector de la pile d'exécution du traitement tactile ...

2
user1021430

J'ai utilisé l'exemple de Barry pour mon nouveau développement. Cela a très bien fonctionné! mais je devais inclure un léger changement, obligé de fermer le clavier uniquement pour le champ de texte en cours d'édition.

Donc, j'ai ajouté à l'exemple de Barry ce qui suit:

- (void) textFieldDidBeginEditing:(UITextField *)textField
{
    _textBeingEdited = textField;
}
-(void) textFieldDidEndEditing:(UITextField *)textField
{
    _textBeingEdited = nil;
}

De plus, j'ai changé la méthode hideKeyboard comme suit:

- (IBAction)hideKeyboard:(id)sender
{
    // Just call resignFirstResponder on all UITextFields and UITextViews in this VC
    // Why? Because it works and checking which one was last active gets messy.
    //UITextField * tf = (UITextField *) sender;
    [_textBeingEdited resignFirstResponder];
}
2
mtorre

Cela marche

Dans cet exemple, aTextField est le seul UITextField ... S'il y en a d'autres ou UITextViews, il reste un peu plus à faire.

// YourViewController.h
// ...
@interface YourViewController : UIViewController /* some subclass of UIViewController */ <UITextFieldDelegate> // <-- add this protocol
// ...
@end

// YourViewController.m

@interface YourViewController ()
@property (nonatomic, strong, readonly) UITapGestureRecognizer *singleTapRecognizer;
@end
// ...

@implementation
@synthesize singleTapRecognizer = _singleTapRecognizer;
// ...

- (void)viewDidLoad
{
    [super viewDidLoad];
    // your other init code here
    [self.view addGestureRecognizer:self.singleTapRecognizer];

{

- (UITapGestureRecognizer *)singleTapRecognizer
{
    if (nil == _singleTapRecognizer) {
        _singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapToDismissKeyboard:)];
        _singleTapRecognizer.cancelsTouchesInView = NO; // absolutely required, otherwise "tap" eats events.
    }
    return _singleTapRecognizer;
}

// Something inside this VC's view was tapped (except the navbar/toolbar)
- (void)singleTapToDismissKeyboard:(UITapGestureRecognizer *)sender
{
    NSLog(@"singleTap");
    [self hideKeyboard:sender];
}

// When the "Return" key is pressed on the on-screen keyboard, hide the keyboard.
// for protocol UITextFieldDelegate
- (BOOL)textFieldShouldReturn:(UITextField*)textField
{
    NSLog(@"Return pressed");
    [self hideKeyboard:textField];
    return YES;
}

- (IBAction)hideKeyboard:(id)sender
{
    // Just call resignFirstResponder on all UITextFields and UITextViews in this VC
    // Why? Because it works and checking which one was last active gets messy.
    [aTextField resignFirstResponder];
    NSLog(@"keyboard hidden");
}
1
user246672

Dans ce cas, il peut y avoir utilisation ScrollView et ajouté à TextField dans ScrollView et je veux Tapotez sur le ScrollView et cliquez sur Afficher Rejeter le clavier. J'ai essayé de créer un exemple de code au cas où. Comme ça,

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var scrollView: UIScrollView!
    @IBOutlet weak var textField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.tap(_:)))
        view.addGestureRecognizer(tapGesture)
        // Do any additional setup after loading the view, typically from a nib.
    }
    func tap(gesture: UITapGestureRecognizer) {
        textField.resignFirstResponder()
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

Votre Storyboard Regardez ça comme si.

enter image description here

1
Ravi Dhorajiya
  • Définir le délégué des champs de texte en vue chargé:

    override func viewDidLoad() 
    {
      super.viewDidLoad()
      self.userText.delegate = self
    }
    
  • Ajouter cette fonction:

    func textFieldShouldReturn(userText: UITextField!) -> Bool 
    {
     userText.resignFirstResponder()
     return true;
    }
    
1
seggy

Ajoutez ce code dans votre fichier ViewController.m:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.view endEditing:YES];
}
1
aashish tamsya
- (void)viewDidLoad
{
    [super viewDidLoad]; 

UITapGestureRecognizer *singleTapGestureRecognizer = [[UITapGestureRecognizer alloc]
                                                          initWithTarget:self
                                                          action:@selector(handleSingleTap:)];
    [singleTapGestureRecognizer setNumberOfTapsRequired:1];
    [singleTapGestureRecognizer requireGestureRecognizerToFail:singleTapGestureRecognizer];

    [self.view addGestureRecognizer:singleTapGestureRecognizer];
}

- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer
{
    [self.view endEditing:YES];
    [textField resignFirstResponder];
    [scrollView setContentOffset:CGPointMake(0, -40) animated:YES];

}
1
Gaurav Gilani

Vous pouvez utiliser la méthode UITapGestureRecongnizer pour supprimer le clavier en cliquant en dehors de UITextField. En utilisant cette méthode chaque fois que l'utilisateur clique en dehors de UITextField, le clavier est ignoré. Ci-dessous l'extrait de code pour l'utiliser.

 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
                                   initWithTarget:self
                                   action:@selector(dismissk)];

    [self.view addGestureRecognizer:tap];


//Method
- (void) dismissk
{
    [abctextfield resignFirstResponder];
    [deftextfield resignFirstResponder];

}
1
Nirzar Gandhi
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

    if let touch = touches.first{
     view.endEditing(true)

     }
}
1
Phani Sai

Envoyez le message resignFirstResponder au champ de texte qui l’a indiqué. S'il vous plaît voir cet article pour plus d'informations.

1
Ke Sun

Pour ceux qui luttent avec cela dans Swift. C'est la réponse acceptée par Jensen2k mais dans Swift.

Swift 2.

    override func viewDidLoad() {
        //.....

        let viewTapGestureRec = UITapGestureRecognizer(target: self, action: #selector(handleViewTap(_:)))
        //this line is important
        viewTapGestureRec.cancelsTouchesInView = false
        self.view.addGestureRecognizer(viewTapGestureRec)

         //.....
    }

    func handleViewTap(recognizer: UIGestureRecognizer) {
        myTextField.resignFirstResponder()
    }
1
lwdthe1
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
    super.view.endEditing(true)
    super.touchesBegan(touches, withEvent: event)
}
0
Derek Dawson

Dans viewDidLoad Swift 4.2 Le code comme celui-ci

let viewTap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action:#selector(dismissKeyboard))
        view.addGestureRecognizer(viewTap)
@objc func dismissKeyboard() {
        view.endEditing(true)
    }
0
CSE 1994

utilisez simplement ce code dans votre fichier .m, il résiliera le champ de texte lorsque l’utilisateur tapera en dehors du champ de texte.

 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
  [textfield resignFirstResponder];
 }
0
Amit Shelgaonkar

Je devais donc simplement résoudre ce problème et aucune des réponses précédentes ne fonctionnait pour moi hors de la boîte. Ma situation: a UISearchBar, plus un certain nombre de commandes à l'écran. Je veux qu'un tapotement en dehors de la barre de recherche ferme le clavier, mais not se propage à l'un des autres contrôles. Lorsque le clavier est masqué, je souhaite que toutes les commandes fonctionnent.

Ce que j'ai fait:

1) Implémentez un gestionnaire tactile personnalisé dans mon contrôleur de vue.

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
{
    if searchBar.isFirstResponder()
    {
        // This causes the first responder, whoever it is, to resign first responder, and hide the keyboard.
        // We also "eat" the touch here and not allow it to propagate further.
        view.endEditing(true)
    }
    else
    {
        // OK to propagate the touch
        super.touchesBegan(touches, withEvent: event)
    }
}

2) Ajout de deux méthodes de délégué (les miennes sont pour le UISearchBar, mais il en existe des similaires pour UITextField). controlContainerView dans le code ci-dessous est un UIView qui a un tas de boutons. Rappelez-vous que le réglage de userInteractionEnabled sur un superview désactive toutes ses sous-vues.

 func searchBarTextDidBeginEditing(searchBar: UISearchBar)
 {
     controlContainerView.userInteractionEnabled = false
     someButton.userInteractionEnabled = false
 }

 func searchBarTextDidEndEditing(searchBar: UISearchBar)
 {
     searchBar.resignFirstResponder()

    // Done editing: enable the other controls again.

    controlContainerView.userInteractionEnabled = false
    someButton.userInteractionEnabled = false
}
0
Macondo2Seattle