Comment fermer le clavier lors de la modification d'un UITextField


181

Je sais que je dois dire à mon UITextField de démissionner du premier répondeur lorsque je veux démonter le clavier, mais je ne sais pas comment savoir quand l'utilisateur a appuyé sur la touche "Terminé" du clavier. Y a-t-il une notification que je peux surveiller?


2
[self.view endEditing: OUI]; en touche a commencé le délégué est la meilleure solution
Zar E Ahmer

Réponses:


351

J'ai mis le délégué de la UITextFieldà ma ViewControllerclasse.

Dans cette classe, j'ai implémenté cette méthode comme suit:

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    [textField resignFirstResponder];
    return NO;
}

Voir l'exemple ci-dessus ... connectez cela en utilisant IntefaceBuilder à l'action sur tout ce que vous utilisez comme contrôleur ... chaque fois que l'utilisateur rejette le système de saisie de texte (appuie sur terminé), cela sera appelé ...
Jason Coco

2
L'un ou l'autre fonctionnera - le champ de texte envoie son action lorsque l'utilisateur frappe la touche Return ("Done", peu importe), et envoie également son délégué -textFieldShouldReturn :.
Noah Witherspoon

BTW - cela fonctionne également pour un UISearchBar. Par exemple, mon code j'avais un membre IBOutlet searchBarTusb; Quand ma 'clé de retour' (UIReturnKeySearch) a été cliquée, - (void) searchBarSearchButtonClicked :, j'ai mis l'instruction [searchBarTusb resignFirstResponder]; Notez également que la «clé de retour» a été définie dans le NIB à l'aide d'Interface Builder.
mobibob

Pourquoi revenir NOau lieu de YES?
Iulian Onofrei

@IulianOnofrei Le comportement par défaut du bouton de retour est d'ajouter un retour de ligne et de garder le clavier à l'écran. En retournant NOvous évitez d'ajouter une ligne retour au texte.
kubi le

47

Si vous connectez l'événement DidEndOnExit du champ de texte à une action (IBAction) dans InterfaceBuilder, il sera envoyé lorsque l'utilisateur rejette le clavier (avec la touche de retour) et l'expéditeur sera une référence à UITextField qui a déclenché l'événement.

Par exemple:

-(IBAction)userDoneEnteringText:(id)sender
{
    UITextField theField = (UITextField*)sender;
    // do whatever you want with this text field
}

Ensuite, dans InterfaceBuilder, liez l'événement DidEndOnExit du champ de texte à cette action sur votre contrôleur (ou tout ce que vous utilisez pour lier des événements à partir de l'interface utilisateur). Chaque fois que l'utilisateur entre du texte et rejette le champ de texte, le contrôleur recevra ce message.


Le seul événement qui semble pouvoir fonctionner est textFieldDidEndEditing, qui indique qu'il n'est envoyé qu'après que UITextField a démissionné du statut de premier répondant. Comment savoir quand je dois démissionner du statut de premier répondant?
kubi

Je suis désolé pour la terminologie ... ce n'est pas une notification réelle (événement) ... Je vais éditer ma réponse avec un exemple rapide et une explication, alors voyez ça :)
Jason Coco

1
Pour clarifier cette réponse, le champ textField envoie l'événement «Did End On Exit» lorsque vous appuyez sur la touche de retour, c'est donc celui que vous devez lier à votre contrôleur. Je pense que cette méthode est plus simple que celle que j'ai décrite ci-dessus.
kubi

2
pouvez-vous modifier cette réponse pour qu'elle mentionne QUEL événement à câbler, s'il vous plaît? C'est évidemment plus agréable que de définir le délégué.
Dan Rosenstark

1
Vous voulez voter pour cette réponse, mais je ne peux pas tant qu'il ne mentionne pas l'événement DidEndOnExit. Quelqu'un avec des privilèges d'édition s'il vous plaît faire le changement si l'OP ne le fait pas?
James Hart

32

Vous pouvez également créer une méthode dans votre contrôleur

 -(IBAction)editingEnded:(id)sender{
    [sender resignFirstResponder]; 
}

puis dans l'inspecteur de connexion dans IB, connectez l'événement «Did End On Exit».


1
C'est presque incorrect, ou du moins ça passe à côté. En vous abonnant à l' DidEndOnExitévénement, vous n'avez pas besoin d'appeler resignFirstResponder. Vous pouvez tester cela en mettant un point d'arrêt symbolique [UIResponder resignFirstResponder]. Notez que même si vous n'appelez pas resignFirstResponder, il est toujours appelé par le système. Ceci est expliqué dans l'excellent (s) livre (s) de Matt Neuburg: apeth.com/iOSBook
Chris Conover

19

kubi, merci. Votre code a fonctionné. Juste pour être explicite (pour les débutants comme) comme vous le dites, vous devez définir le UITextField's delegatepour être égal au ViewController dans lequel le champ de texte réside. Vous pouvez le faire où bon vous semble. J'ai choisi la viewDidLoadméthode.

- (void)viewDidLoad 
{
    // sets the textField delegates to equal this viewController ... this allows for the keyboard to disappear after pressing done
    daTextField.delegate = self;
}

Si vous avez ajouté un champ de texte à votre storyboard ou NIB, vous pouvez également y définir le champ de texte delegate. Vous n'êtes pas obligé de le faire par programme, comme illustré ci-dessus. Les deux approches fonctionnent très bien.
Rob

18

Voici une astuce pour obtenir un comportement de renvoi automatique du clavier sans code du tout. Dans la pointe, modifiez l'objet proxy Premier répondeur dans l'inspecteur d'identité, en ajoutant une nouvelle action de premier répondant; appelons ça dummy:. Reliez maintenant l'événement Did End on Exit du champ de texte à l' dummy:action de l'objet proxy First Responder. C'est tout! Étant donné que l'événement Did End on Exit du champ de texte a maintenant une paire action-cible, le champ de texte ferme automatiquement son clavier lorsque l'utilisateur appuie sur Retour; et comme il n'y a pas de pénalité pour ne pas trouver de gestionnaire pour un message envoyé dans la chaîne de répondeurs, l'application ne plante pas même s'il n'y a aucune implémentation de dummy:nulle part.


@matt J'ai découvert que SI j'ajoute une séquence de déroulement ET connecte l'événement didEndOnExit ALORS la séquence de déroulement sera déclenchée en appuyant sur Retour. Sans la connexion d'événement, le segue n'est pas déclenché. Super mais hein? Des remarques? BTW: J'ai vos livres Swift (terminé) et iOS10 (sur chap 6). Ils m'ont énormément aidé!
Verticon

@Verticon la question et la réponse n'ont rien à voir avec les segues, donc je ne comprends pas le problème ...: (il s'agit uniquement de licenciement du clavier
mat

@matt Désolé, mec. J'étais sur le dos parce que 1) je suis tombé sur ce fil pendant que je m'occupais de la façon de gérer la clé de retour de UITextField; et 2) c'était une chance d'interagir avec vous (merci pour les livres). Il n'y a pas de "problème". Juste un manque de compréhension de ma part sur pourquoi / comment cela fonctionne comme il le fait.
Verticon

@Verticon Je m'excuse de ne pas pouvoir vous aider. N'hésitez pas à formuler une nouvelle question avec plus d'informations (projet de démonstration?) Et à me faire un message, si je peux être utile.
mat


11

Il suffit d'ajouter

[textField endEditing:YES];

où vous souhaitez désactiver le clavier et afficher la vue du sélecteur.


10

Dans Swift, vous pouvez écrire une IBAction dans le contrôleur et définir l' événement Did End On Exit du champ de texte sur cette action

@IBAction func returnPressed(sender: UITextField) {
    self.view.endEditing(true)
}

5

Swift 4.2 et cela fonctionnera à 100%

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var textField: UITextField!


    override func viewDidLoad() {
        super.viewDidLoad()

        self.textField.delegate = self

    }

    // hide key board when the user touches outside keyboard

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

    // user presses return key

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

}

4

Vous pouvez aussi utiliser

 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
  {

   [self.yourTextField resignFirstResponder];

  }

Le meilleur si vous avez de nombreux champs Uitext:

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

2

Voici ce que j'ai dû faire pour le faire fonctionner, et je pense que c'est nécessaire pour toute personne possédant un pavé numérique pour un clavier (ou tout autre sans bouton terminé:

  1. J'ai changé l'UIView dans le ViewController en UIControl.
  2. J'ai créé une fonction appelée

    -(IBAction)backgroundIsTapped:(id)sender

Cela a également été défini dans le fichier .h.

Après cela, j'ai lié au bit «touch down» pour le ViewController dans Interface Builder.

Dans la fonction 'background is taped', je mets ceci:

    [answerField resignFirstResponder];

N'oubliez pas de remplacer 'answerField' par le nom de l'UITextField dont vous souhaitez supprimer le clavier (assurez-vous évidemment que votre UITextField est défini comme ci-dessous :)

    IBOutlet UITextField * <nameoftextfieldhere>;

Je sais que ce sujet est probablement mort il y a longtemps ... mais j'espère que cela aidera quelqu'un, quelque part!


..mais cela ne fonctionne pas très bien si l'utilisateur appuie sur un autre contrôle.
ragnarius

2

Vous remarquerez que la méthode "textFieldShouldReturn" fournit l'objet de champ de texte qui a appuyé sur la touche DONE. Si vous définissez le TAG, vous pouvez activer ce champ de texte. Ou vous pouvez suivre et comparer le pointeur de l'objet avec une valeur de membre stockée par son créateur.

Ma démarche est la suivante pour une auto-apprentissage:

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    NSLog(@"%s", __FUNCTION__);

    bool fDidResign = [textField resignFirstResponder];

    NSLog(@"%s: did %resign the keyboard", __FUNCTION__, fDidResign ? @"" : @"not ");

    return fDidResign;
}

En attendant, je mets le test de «validation» qui nie la démission qui suit. Ce n'est qu'à titre d'illustration, donc si l'utilisateur tape NON! sur le terrain, il ne rejettera pas. Le comportement était comme je le voulais, mais la séquence de sortie n'était pas comme je m'y attendais.

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
    NSLog(@"%s", __FUNCTION__);

    if( [[textField text] isEqualToString:@"NO!"] ) {
        NSLog(@"%@", textField.text);
        return NO;
    } else {
        return YES;
    }
}

Voici ma sortie NSLog pour ce refus suivi de l'acceptation. Vous remarquerez que je retourne le résultat de la démission, mais je m'attendais à ce qu'il me retourne FALSE pour faire rapport à l'appelant?! En dehors de cela, il a le comportement nécessaire.

13.313 StudyKbd [109: 207] - [StudyKbdViewController textFieldShouldReturn:]
13.320 StudyKbd [109: 207] - [StudyKbdViewController textFieldShouldEndEditing:]
13.327 StudyKbd [109: 207] NON!
13.333 StudyKbd [109: 207] - [StudyKbdViewController textFieldShouldReturn:]: a démissionné du clavier
59.891 StudyKbd [109: 207] - [StudyKbdViewController textFieldShouldReturn:]
59.897 StudyKbd [109: 207] - [StudyKbdViewController textFieldShouldEndEditing:]
59.917 StudyKbd [109: 207] - [StudyKbdViewController doneEditText]: NON
59.928 StudyKbd [109: 207] - [StudyKbdViewController textFieldShouldReturn:]: a démissionné du clavier

1
pouvez-vous expliquer ... si je retourne NON ou OUI dans les deux cas, les mêmes choses se produisent alors quel est le besoin de renvoyer oui dans la méthode déléguée textFieldShouldReturn
K. Jaiswal

1

Voici une façon assez propre de terminer l'édition avec la clé de retour ou une touche en arrière-plan.

Dans le générateur d'interface, intégrez vos champs dans une vue de la classe UIFormView

Que signifie cette classe:

  • S'attache automatiquement en tant que délégué de champs (soit réveillé de la pointe, soit ajouté manuellement)
  • Conserver une référence sur le champ actuellement modifié
  • Ignorer le clavier au retour ou toucher en arrière-plan

Voici le code:

Interface

#import <UIKit/UIKit.h>

@interface UIFormView : UIView<UITextFieldDelegate>

-(BOOL)textFieldValueIsValid:(UITextField*)textField;
-(void)endEdit;

@end

la mise en oeuvre

#import "UIFormView.h"

@implementation UIFormView
{
    UITextField* currentEditingTextField;
}

// Automatically register fields

-(void)addSubview:(UIView *)view
{
    [super addSubview:view];
    if ([view isKindOfClass:[UITextField class]]) {
        if ( ![(UITextField*)view delegate] ) [(UITextField*)view setDelegate:self];
    }
}

// UITextField Protocol

-(void)textFieldDidBeginEditing:(UITextField *)textField
{
    currentEditingTextField = textField;
}

-(void)textFieldDidEndEditing:(UITextField *)textField
{
    currentEditingTextField = NULL;
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self endEdit];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    if ([self textFieldValueIsValid:textField]) {
        [self endEdit];
        return YES;
    } else {
        return NO;
    }
}

// Own functions

-(void)endEdit
{
    if (currentEditingTextField) {
        [currentEditingTextField endEditing:YES];
        currentEditingTextField = NULL;
    }
}


// Override this in your subclass to handle eventual values that may prevent validation.

-(BOOL)textFieldValueIsValid:(UITextField*)textField
{
    return YES;
}

@end
  • En sous-classant le formulaire et en remplaçant la textFieldValueIsValid:méthode, vous pouvez éviter la fin de l'édition si la valeur n'est pas correcte pour le champ donné.

  • Si un champ a un délégué défini dans Interface Builder, le formulaire ne le change pas. Je ne vois pas beaucoup de raisons de définir un délégué différent dans un domaine particulier, mais pourquoi pas…

Il existe de nombreuses façons d'améliorer cette classe de vue de formulaire - Joindre un délégué, faire une mise en page, gérer le moment où les claviers couvrent un champ (en utilisant le cadre currentEditingTextField), démarrer automatiquement l'édition pour le champ suivant, ...

Je le garde personnellement dans mon framework, et je le sous-classe toujours pour ajouter des fonctionnalités, il est assez souvent utile "tel quel".

J'espère que cela aidera. Salut à tous


1
Classe utile. Un petit point, vous ne devriez pas préfixer vos propres classes avec "UI". Dans objective-c vous devez utiliser votre propre préfixe ("TL"?), En Swift, n'utilisez rien.
kubi

Merci @kubi. C'est vrai. C'est MF dans mon cadre, comme MooseFactory;)
Moose

1

si vous voulez toute l'édition de dans un UIViewController, vous pouvez utiliser.

[[self view]endEditing:YES];

et si vous voulez ignorer un masque UITextField correspondant, utilisez.

1. ajoutez un délégué dans votre viewcontroller.h

<UITextFieldDelegate>
  1. rendre la délégation impossible à votre champ de texte.

    self.yourTextField.delegate = self;

  2. ajoutez cette méthode dans votre viewcontroller.

    - (BOOL) textFieldShouldEndEditing: (UITextField *) textField {[textField resignFirstResponder]; retour OUI;}


1

Définir par programme le délégué de UITextField dans swift 3

Implémentez UITextFieldDelegate dans votre fichier ViewController.Swift (par exemple, la classe ViewController: UIViewController, UITextFieldDelegate {)

 lazy var firstNameTF: UITextField = {

    let firstname = UITextField()
    firstname.placeholder = "FirstName"
    firstname.frame = CGRect(x:38, y: 100, width: 244, height: 30)
    firstname.textAlignment = .center
    firstname.borderStyle = UITextBorderStyle.roundedRect
    firstname.keyboardType = UIKeyboardType.default
    firstname.delegate = self
    return firstname
}()

lazy var lastNameTF: UITextField = {

    let lastname = UITextField()
    lastname.placeholder = "LastName"
    lastname.frame = CGRect(x:38, y: 150, width: 244, height: 30)
    lastname.textAlignment = .center
    lastname.borderStyle = UITextBorderStyle.roundedRect
    lastname.keyboardType = UIKeyboardType.default
    lastname.delegate = self
    return lastname
}()

lazy var emailIdTF: UITextField = {

    let emailid = UITextField()
    emailid.placeholder = "EmailId"
    emailid.frame = CGRect(x:38, y: 200, width: 244, height: 30)
    emailid.textAlignment = .center
    emailid.borderStyle = UITextBorderStyle.roundedRect
    emailid.keyboardType = UIKeyboardType.default
    emailid.delegate = self
    return emailid
}()

// Marque: - gestion du délégué textField ..

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

func textFieldShouldReturn(_ textField: UITextField) -> Bool {

    if textField == firstNameTF {

        lastNameTF.becomeFirstResponder()
    }

    else if textField == lastNameTF {

        emailIdTF.becomeFirstResponder()
    }
    else {
        view.emailIdTF(true)
    }
    return true
}

0

Créez une fonction hidekeyboard et liez-la au champ de texte dans le fichier .xib et sélectionnez DidEndOnExit

-(IBAction)Hidekeyboard    
{    
      textfield_name.resignFirstResponder;    
}  

0

Si vous avez créé la vue à l'aide d'Interface Builder, utilisez ce qui suit: Créez simplement une méthode,

-(IBAction)dismissKeyboard:(id)sender
{
[sender resignFirstResponder];
}

Cliquez avec le bouton droit de la souris sur le champ de texte dans la vue, définissez l'événement comme Did End on Exit, et connectez-le à la méthode «ignoreKeyboard».

Le meilleur guide pour les débutants est "Head First iPhone and iPad Development, 2nd Edition"


0

essaye ça

- (BOOL) textView: (UITextView*) textView shouldChangeTextInRange: (NSRange) range replacementText: (NSString*) text
{
    if ([text isEqualToString:@"\n"]) {
        [textView resignFirstResponder];
        return NO;
    }
    return YES;
}

0
//====================================================
//                  textFieldShouldReturn:
//====================================================
-(BOOL) textFieldShouldReturn:(UITextField*) textField { 
    [textField resignFirstResponder];
    if(textField.returnKeyType != UIReturnKeyDone){
        [[textField.superview viewWithTag: self.nextTextField] becomeFirstResponder];
    }
    return YES;
}

0

Quiconque recherche Swift 3

1) Assurez-vous que le délégué de votre UITextField est câblé à votre ViewController dans le Storyboard

2) Implémentez UITextFieldDelegate dans votre fichier ViewController.Swift (par exemple la classe ViewController: UIViewController, UITextFieldDelegate {)

3) Utilisez la méthode déléguée ci-dessous

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

0

Voici comment je supprime le clavier dans Swift 4.2 et cela fonctionne pour moi:

    override func viewDidLoad() {
    super.viewDidLoad()

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

    view.addGestureRecognizer(tap)
    }

    @objc func dismissKeyboard (_ sender: UITapGestureRecognizer) {
    numberField.resignFirstResponder()
    }

-2

Swift 3, iOS 9+

@IBAction private func noteFieldDidEndOnExit(_ sender: UITextField) {}

UPD: Cela fonctionne toujours bien pour moi. Je pense que le gars qui a consacré cette réponse n'a tout simplement pas compris qu'il devait lier cette action au UITextField au storyboard.


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.