Ignorer le clavier en touchant l'arrière-plan de UITableView


105

J'ai un UITableViewavec des UITextFieldcellules. Je voudrais supprimer le clavier lorsque l'arrière-plan du UITableViewest touché. J'essaye de faire ceci en créant une UIButtontaille de la UITableViewet en la plaçant derrière le UITableView. Le seul problème est qu'il UIButtoncapte toutes les touches même lorsque le toucher est sur UITableView. Qu'est-ce que je fais mal?

Merci!


Questions et réponses répétées: Q1 , Q2 , Q3 .
Yantao Xie

C'est la meilleure réponse stackoverflow.com/a/12851794/1418457
onmyway133

Réponses:


203

Cela se fait facilement en créant un objet UITapGestureRecognizer (par défaut, cela détectera un «geste» en un seul clic, donc aucune personnalisation supplémentaire n'est requise), en spécifiant une cible / action pour le moment où le geste est déclenché, puis en attachant l'objet de reconnaissance de mouvement à votre vue de table.

Par exemple, peut-être dans votre viewDidLoadméthode:

UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard)];
[self.tableView addGestureRecognizer:gestureRecognizer];

Et la hideKeyboardméthode pourrait ressembler à ceci:

- (void) hideKeyboard {
    [textField1 resignFirstResponder];
    [textField2 resignFirstResponder];
    ...
    ...
}

Notez que le geste n'est pas déclenché lorsque vous touchez l'intérieur d'un UITextFieldobjet. Il est déclenché en UITableViewarrière - plan, en pied de page, en en-tête et à l' UILabelsintérieur des cellules, etc.


4
Quand j'ai essayé cela, j'ai trouvé que cela empêchait le tableau de sélectionner des cellules: (. Solution géniale sinon
Brian

109
Comme solution ci-dessous, vous pouvez améliorer ce travail en définissant:gestureRecognizer.cancelsTouchesInView = NO;
Zebs

3
Et n'oubliez pas de relâcher le gestureRecognizer une fois qu'il est attaché à tableView.
Paul Lynch

39
Pour la hideKeyboardméthode, au lieu de communiquer directement avec les champs de texte, vous pouvez le faire [self.view endEditing:NO];. Extrait de la documentation Apple: " Cette méthode examine la vue actuelle et sa hiérarchie de sous-vues pour le champ de texte qui est actuellement le premier répondeur. S'il en trouve un, il demande à ce champ de texte de démissionner en tant que premier répondant. Si le paramètre de force est défini sur OUI, le champ de texte n'est même jamais demandé; il est obligé de démissionner. "
Gobot

1
en utilisant cette méthode, ma méthode "didSelectRowAtIndexPath" n'est pas appelée. une solution pour cela ??
uniruddh

127

La solution UITapGestureRecognizer fonctionne avec la sélection de cellule de tableau si vous définissez:

gestureRecognizer.cancelsTouchesInView = NO;

1
Cela permet de toucher la cellule, mais le geste est également reconnu, peut-être devrions-nous implémenter ces méthodes de déléguéshouldReceiveTouch
onmyway133

61

Voici une meilleure façon de procéder. Fais juste ça

[self.view endEditing:YES];

ou

[[self.tableView superView] endEditing:YES];

où dois-je mettre ce code? désolé je suis débutant. Et veuillez fournir le code rapide.
John

54

Vous pouvez également le faire à partir de Storyboard: entrez la description de l'image ici


1
Quoi que je choisisse: Ignorer lors du glissement, Ignorer de manière interactive, lorsque je touche la cellule du tableau, elle est sélectionnée. J'utilise Xcode 8, swift 3. veuillez aider
John

22

Comme UITableViewc'est une sous-classe de UIScrollView, l'implémentation d'une méthode de délégué ci-dessous fournit une solution extrêmement simple et rapide. Pas besoin même d'impliquer resignFirstResponderpuisque la hiérarchie de vue introspecte et trouve le répondeur actuel et lui demande de démissionner de son statut de répondeur.

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    [self.view endEditing:YES];
}

Et n'oubliez pas d'ajouter UIScrollViewDelegateau fichier d'en-tête.


2
Cela peut être fait via cette ligne unique, comme indiqué par @Joe Masilotti si vous ciblez iOS7 et supérieur: self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
atulkhatri

Que se passe-t-il si vous appuyez sur un champ de texte en bas de l'écran qui est censé défiler vers le haut pour afficher le clavier? - Votre clavier sera masqué.
Islam Q.

Swift 4 - self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissMode.onDrag
RobLabs

13

Tout d'abord, écoutez scrollViewWillBeginDraggingdans votre UIViewControlleren ajoutant UIScrollViewDelegate:

Dans le fichier .h:

@interface MyViewController : UIViewController <UIScrollViewDelegate> 

Dans le fichier .m:

- (void)scrollViewWillBeginDragging:(UIScrollView *)activeScrollView {

    [self dismissKeyboard];

}

Ensuite, écoutez les autres interactions:

- (void)setupKeyboardDismissTaps {

    UISwipeGestureRecognizer *swipeUpGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
    swipeUpGestureRecognizer.cancelsTouchesInView = NO;
    swipeUpGestureRecognizer.direction = UISwipeGestureRecognizerDirectionUp;
    [self.tableView addGestureRecognizer:swipeUpGestureRecognizer];

    UISwipeGestureRecognizer *swipeDownGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
    swipeDownGestureRecognizer.cancelsTouchesInView = NO;
    swipeDownGestureRecognizer.direction = UISwipeGestureRecognizerDirectionDown;
    [self.tableView addGestureRecognizer:swipeDownGestureRecognizer];

    UISwipeGestureRecognizer *swipeLeftGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
    swipeLeftGestureRecognizer.cancelsTouchesInView = NO;
    swipeLeftGestureRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
    [self.tableView addGestureRecognizer:swipeLeftGestureRecognizer];

    UISwipeGestureRecognizer *swipeRightGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
    swipeRightGestureRecognizer.cancelsTouchesInView = NO;
    swipeRightGestureRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
    [self.tableView addGestureRecognizer:swipeRightGestureRecognizer];


    UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
    tapGestureRecognizer.cancelsTouchesInView = NO;
    [self.tableView addGestureRecognizer:tapGestureRecognizer];

}

Puis implémentez dismissKeyboard:

- (void)dismissKeyboard {

    NSLog(@"dismissKeyboard");

    [yourTextFieldPointer resignFirstResponder];

}

Et si, comme moi, vous vouliez supprimer le clavier d'un UITextField dans une cellule de tableau personnalisée:

- (void)dismissKeyboard {

    NSLog(@"dismissKeyboard");

    CustomCellClass *customCell = [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
    [customCell.textFieldInCell resignFirstResponder]; 

}

J'espère que cela aide quiconque cherche !!



8

Voici la version rapide pour votre plaisir de codage:

Il ajoute un outil de reconnaissance des gestes, puis ferme le clavier. Aucune prise pour le TextField n'est requise!

override func viewDidLoad() {
    super.viewDidLoad()
    view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "handleTap:"))
}

func handleTap(sender: UITapGestureRecognizer) {
    if sender.state == .Ended {
        view.endEditing(true)
    }
    sender.cancelsTouchesInView = false
}

1
Cela fonctionne même avec une tableViewCell personnalisée! J'ai passé tellement de temps à essayer de comprendre cela. Merci beaucoup! Tu es mon héros. youtu.be/EqWRaAF6_WY
peacetype

8

Il existe une version Swift 3 sans bloquer les robinets sur les cellules.

En viewDidLoad()méthode:

let dismissKeyboardGesture = UITapGestureRecognizer(target: self, action: #selector(hideKeyboard))
dismissKeyboardGesture.cancelsTouchesInView = false
tableView.addGestureRecognizer(dismissKeyboardGesture)

Et hideKeyboardressemble à ceci:

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

7

Je l'ai fait comme ça:

Créez une méthode dans votre TableViewController pour désactiver le premier répondeur (qui serait votre TextBox à ce stade)

- (BOOL)findAndResignFirstResonder:(UIView *)stView {
    if (stView.isFirstResponder) {
        [stView resignFirstResponder];
        return YES;     
    }

    for (UIView *subView in stView.subviews) {
        if ([self findAndResignFirstResonder:subView]) {
            return YES;
        }
    }
    return NO;
}

En tableView:didSelectRowAtIndexPath:appeler la méthode précédente:

- (void)tableView:(UITableView *)tableView
                             didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    ...
    [self findAndResignFirstResonder: self.view];
    ...
}

vous le faites mal comme vous le demandez. vous ne mettez pas de bouton sur la vue, vous dites à la vue de supprimer le clavier comme le dit cette réponse

2
Cela fonctionne à merveille si vous appuyez dans une cellule de vue de tableau (et à l'extérieur de tout UITextField dans cette cellule de vue de tableau). Cependant, si je touche l'arrière-plan de la vue du tableau (qui est souvent une cible plus facile à atteindre - yay la loi de Fitts!), Pas de chance. C'est vrai, c'est normal, puisque nous effectuons cette opération dans tableView: didSelectRowAtIndexPath:. Si cela peut être ajusté d'une manière ou d'une autre pour fonctionner en tapotant n'importe où ailleurs dans la vue du tableau (qui autrement ne voudrait pas se concentrer sur le clavier), je pense que nous avons un gagnant ici!
Joe D'Andrea

J'ai le même problème que jdandrea. Cela didSelectRowAtIndexPathne se déclenche pas si vous appuyez sur le TableView lui-même.
zekel

si didSelectRowAtIndexPath n'est pas suffisant, faites de même avec touchesBegan!
Amogh Talpallikar

5

J'avais un UITableViewControlleret la mise en œuvre touchesBegan:withEvent:n'a pas fonctionné pour moi.

Voici ce qui a fonctionné:

Rapide:

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    view.endEditing(true)
}

Objectif c:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [self.view endEditing:YES];
}

Bonne idée, j'aime ça.
HotFudgeSunday

4
@interface DismissableUITableView : UITableView {
}
@end

@implementation DismissableUITableView

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

@end

Ensuite, assurez-vous que dans votre fichier Nib vous définissez le type de votre UITableView sur DismissableUITableView ..... peut-être que j'aurais pu penser à un meilleur nom pour cette classe, mais vous comprenez.


4

Si vous ciblez iOS7, vous pouvez utiliser l'un des éléments suivants:

tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;

tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;

Le premier animera le clavier hors de l'écran lorsque la vue de la table défilera et le dernier masquera le clavier comme l'application de messages en stock.

Notez que ceux-ci sont de UIScrollView, qui UITableViewhérite de.


agréable. J'ai réussi à le casser en faisant glisser vers le bas de haut vers le haut de l'écran jusqu'à ce que le clavier commence à descendre, puis en remontant jusqu'à ce que le clavier monte un peu, puis en lâchant prise. le scrollview ne revient pas en haut comme il se doit.
Sam

3

Essaye ça:

viewDidLoad(){

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

    tableView.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)

}

2

UITableView est une sous-classe de UIScrollView.

La façon dont je l'ai fait était d'écouter un événement de défilement par l'utilisateur, puis de resignFirstResponder. Voici la méthode UIScrollViewDelegate à implémenter dans votre code;

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView

En abordant ces types de problèmes, j'ai trouvé que le meilleur moyen est de rechercher les protocoles délégués pour chaque objet et ceux des classes parentes (dans ce cas, UITableViewDelegate, UIScrollViewDelegate. Le nombre d'événements déclenchés par les objets NS est assez important et complet. C'est également plus facile de mettre en œuvre un protocole puis de sous-classer quoi que ce soit.


2

J'ai eu le même problème et voici ma solution, cela fonctionne parfaitement pour moi:

Dans le contrôleur de vue ou de vue que vous avez implémenté <UITextFieldDelegate>

(Dans mon cas, j'ai une coutume UITableViewCellappelée TextFieldCell),

Déclarez le UITapGestureRecognizercomme propriété:

@interface TextFieldCell : UITableViewCell <UITextFieldDelegate>
{
    UITextField *theTextField;
    UITapGestureRecognizer *gestureRecognizer;
}
@property (nonatomic,retain) UITextField *theTextField;
@property (nonatomic,retain) UITapGestureRecognizer *gestureRecognizer; 

Et initialisez-le dans votre vue / contrôleur:

self.gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(closeKeyboard:)];

Dans la - (void)textFieldDidBeginEditing:(UITextField *)textFieldméthode, utilisez superViewpour passer à votre tableView et appelez addGestureRecognizer:

[self.superview.superview addGestureRecognizer:gestureRecognizer];

Et dans le - (void)textFieldDidEndEditing:(UITextField *)textField, supprimez simplement le module de reconnaissance de mouvement:

[self.superview.superview removeGestureRecognizer:gestureRecognizer];

J'espère que ça aide.


Cela l'a fait pour moi. Merci hac.jack
gilsaints88

2

Je voulais que ma cellule ouvre le clavier lorsqu'une partie de la cellule est sélectionnée et la ferme si vous cliquez n'importe où hors de la cellule. Pour ouvrir le clavier:

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];
    if (selected)
    {
        [self.textField becomeFirstResponder];
    }
}

(REMARQUE: j'ai sous-classé la cellule mais vous pouvez facilement y parvenir dans la tableView:didSelectRowAtIndexPath:méthode déléguée de UITableView)

Cela signifiait qu'avec les meilleures solutions, si vous cliquez deux fois sur la cellule, le clavier tremblerait lorsque, d'abord, le module de reconnaissance de gestes tentait de fermer le clavier, puis la cellule était resélectionnée et essayait d'ouvrir le clavier.

La solution consiste à vérifier si le clic s'est produit à l'intérieur de la cellule actuellement sélectionnée:

- (void)viewDidLoad
{
    [super viewDidLoad];
    //gesture recognizer to close the keyboard when user taps away
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                          action:@selector(dismissKeyboard:)];
    tap.cancelsTouchesInView = NO;
    [self.tableView addGestureRecognizer:tap];
}

-(void)dismissKeyboard:(UIGestureRecognizer*)tapGestureRecognizer
{
    if (!CGRectContainsPoint([self.tableView cellForRowAtIndexPath:[self.tableView indexPathForSelectedRow]].frame, [tapGestureRecognizer locationInView:self.tableView]))
    {
        [self.view endEditing:YES];
    }
}

2

J'ai trouvé une solution qui fonctionne très bien.

Est nécessaire pour utiliser la UIGestureRecognizerDelegate et la méthode - gestureRecognizer: shouldReceiveTouch: .

Ajoutez le module de reconnaissance de mouvement à TableView comme suit:

UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard)];
tapGestureRecognizer.cancelsTouchesInView = NO;
tapGestureRecognizer.delegate = self;
[self.suggestedTableView addGestureRecognizer:tapGestureRecognizer];
[tapGestureRecognizer release];

Ensuite, implémentez la méthode de délégué shouldReceiveTouch pour rejeter les touches effectuées dans la classe UITableViewCell. La méthode hideKeyboard ne sera appelée que lorsque le toucher aura été effectué en dehors de la classe UITableViewCell.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    if([touch.view isKindOfClass:[UITableViewCell class]]) {
        return NO;
    }
    // UITableViewCellContentView => UITableViewCell
    if([touch.view.superview isKindOfClass:[UITableViewCell class]]) {
        return NO;
    }
    // UITableViewCellContentView => UITableViewCellScrollView => UITableViewCell
    if([touch.view.superview.superview isKindOfClass:[UITableViewCell class]]) {
        return NO;
    }
    return YES; // handle the touch
}

- (void) hideKeyboard{
    [textField resignFirstResponder];
}

2

UITableViewa une backgroundViewpropriété pratique , avec laquelle j'ai obtenu ce comportement sans jouer avec la sélection de cellules, comme indiqué ci-dessous dans Swift:

let tableBackTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(hideKeyboard))
tableView.backgroundView = UIView()
tableView.backgroundView?.addGestureRecognizer(tableBackTapRecognizer)


1

Utiliser simplement un UITapGestureRecognizer et cancelsTouchesInView = NOsignifie que les tapotements sur les cellules et UITextViews déclenchent également le masquage. C'est mauvais si vous avez plusieurs UITextViews et que vous appuyez sur le suivant. Le clavier commencera à se cacher, puis le textView suivant deviendra le premier répondeur et le clavier redeviendra visible. Pour éviter cela, vérifiez l'emplacement du robinet et ne masquez le clavier que si le robinet n'est pas sur une cellule:

// init
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTapTableView:)];
tapRecognizer.cancelsTouchesInView = NO;
[self.tableView addGestureRecognizer:tapRecognizer];


// Hide on tap
- (void)didTapTableView:(UITapGestureRecognizer *)tap
{
    CGPoint point = [tap locationInView:tap.view];
    [self.view endEditing:!CGRectContainsPoint([self.tableView rectForRowAtIndexPath:[self.tableView indexPathForRowAtPoint:point]], point)];
}

Pour scrollViewWillBeginDragging:être déclenchée, la scrollEnabledpropriété de tableView doit êtreYES

// Hide on scroll
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    [self.view endEditing:YES];
}

Parfait pour moi. Ajout d'une texbox à la cellule tableview; si je touche à l'extérieur du clavier, rejeter
Nicola

0

Pourquoi voulez-vous créer une table pleine de champs de texte? Vous devez utiliser une vue détaillée pour chaque ligne contenant les champs de texte. Lorsque vous poussez votre vue détaillée, assurez-vous d'appeler "[myTextField devenirFirstResponder]" afin que l'utilisateur puisse commencer à modifier en un seul clic à partir de la liste du tableau.


C'est précisément ce que fait l'application Contacts d'Apple. Je ne dirais pas qu'il est plein de champs de texte en soi, mais il les utilise à bon escient.
Joe D'Andrea

2
La modification de texte en ligne dans une vue de tableau est beaucoup plus rapide et intuitive que de pousser des vues de détail pour chaque champ de texte que l'utilisateur souhaite modifier ... il suffit de demander à votre formulaire HTML le plus proche, ou les champs de texte dans les volets des préférences de l'iPhone, ou dans l'application Contacts, ou etc etc etc ... c'est vraiment dommage qu'Apple n'en ait pas fait un type de cellule standard, mais il y a beaucoup d'informations sur le Web pour y parvenir.
glenc

0

Si vous êtes prêt à sous-classer (ugh!) Votre vue de table, quelque chose comme ça pourrait fonctionner:

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

   BOOL backgroundTouched = YES;

   for (UITouch *touch in touches) {
      CGPoint location = [touch locationInView:self];
      for (UITableViewCell *cell in self.visibleCells) {
         if (CGRectContainsPoint(cell.frame, location)) {
            backgroundTouched = NO;
            break;
         }
      }
   }

   if (backgroundTouched) {
      for (UITableViewCell *cell in self.visibleCells) {
         // This presumes the first subview is the text field you want to resign.
         [[cell.contentView.subviews objectAtIndex:0] resignFirstResponder];
      }
   }

   [super touchesBegan:touches withEvent:event];
}

0

Si vous voulez fermer le clavier pendant que vous appuyez sur la touche de retour, vous pouvez simplement ajouter le code suivant dans textField devrait retourner la méthode c'est-à-dire:

- (BOOL)textFieldShouldReturn:(UITextField *)atextField
{
   [textField resignFirstresponder];
}

Certains champs de texte peuvent avoir une vue de sélection ou une autre comme sous-vue, donc dans ce cas, la méthode ci-dessus ne fonctionne pas, donc dans ce cas, nous devons utiliser la classe UITapGestureRecognizer, c'est-à-dire ajouter l'extrait de code suivant à la méthode viewDidLoad, c'est-à-dire:

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

    [self.view addGestureRecognizer:tap];

Maintenant, ajoutez simplement le répondeur démissionnaire à la méthode de sélection, à savoir:

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

J'espère que cela aide, merci :)


0

Beaucoup de réponses intéressantes. Je voudrais compiler différentes approches dans la solution qui, selon moi, correspond le mieux à un scénario UITableView (c'est celui que j'utilise habituellement): ce que nous voulons généralement, c'est masquer le clavier dans deux scénarios: en tapant en dehors des éléments de l'interface utilisateur de texte, ou en faisant défiler l'UITableView vers le bas / vers le haut. Le premier scénario que nous pouvons facilement ajouter via un TapGestureRecognizer, et le second via la méthode UIScrollViewDelegate scrollViewWillBeginDragging :. Premier ordre du jour, la méthode pour masquer le clavier:

   /**
     *  Shortcut for resigning all responders and pull-back the keyboard
     */
    -(void)hideKeyboard
    {
        //this convenience method on UITableView sends a nested message to all subviews, and they resign responders if they have hold of the keyboard
        [self.tableView endEditing:YES];

    }

Cette méthode démissionne de toute interface utilisateur textField des sous-vues dans la hiérarchie de vues UITableView, c'est donc plus pratique que de résigner chaque élément indépendamment.

Ensuite, nous nous occupons du rejet via un geste Tap extérieur, avec:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self setupKeyboardDismissGestures];

}

- (void)setupKeyboardDismissGestures
{

//    Example for a swipe gesture recognizer. it was not set-up since we use scrollViewDelegate for dissmin-on-swiping, but it could be useful to keep in mind for views that do not inherit from UIScrollView
//    UISwipeGestureRecognizer *swipeUpGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard)];
//    swipeUpGestureRecognizer.cancelsTouchesInView = NO;
//    swipeUpGestureRecognizer.direction = UISwipeGestureRecognizerDirectionUp;
//    [self.tableView addGestureRecognizer:swipeUpGestureRecognizer];

    UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard)];
    //this prevents the gestureRecognizer to override other Taps, such as Cell Selection
    tapGestureRecognizer.cancelsTouchesInView = NO;
    [self.tableView addGestureRecognizer:tapGestureRecognizer];

}

La définition de tapGestureRecognizer.cancelsTouchesInView sur NO permet d'éviter que gestureRecognizer ne remplace le fonctionnement interne normal de UITableView (par exemple, ne pas interférer avec la sélection de cellule).

Enfin, pour gérer le masquage du clavier lors du défilement haut / bas de UITableView, nous devons implémenter le protocole UIScrollViewDelegate scrollViewWillBeginDragging: méthode, comme:

fichier .h

@interface MyViewController : UIViewController <UIScrollViewDelegate>

fichier .m

#pragma mark - UIScrollViewDelegate

-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    [self hideKeyboard];
}

J'espère que ça aide! =)


0

Voici comment j'ai finalement réalisé des œuvres. J'ai combiné des suggestions et des codes de différentes réponses. Fonctionnalités: suppression du clavier, déplacement des champs de texte au-dessus du clavier lors de l'édition et réglage du type de retour du clavier "Suivant" et "Terminé". REMPLACER "..." avec plus de champs

static const CGFloat ANIMATION_DURATION = 0.4;
static const CGFloat LITTLE_SPACE = 5;
CGFloat animatedDistance;
CGSize keyboardSize;

@interface ViewController () <UITextFieldDelegate>
 @property (weak, nonatomic) IBOutlet UITextField *firstNameTXT;
  .....// some other text fields
 @property (weak, nonatomic) IBOutlet UITextField *emailTXT;
@end

@implementation ViewController
- (void)viewDidLoad{
.....
// add tap gesture to help in dismissing keyboard
UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc]
                                       initWithTarget:self
                                       action:@selector(tapScreen:)];// outside textfields

[self.view addGestureRecognizer:tapGesture];

// set text fields return key type to Next, last text field to Done
[self.firstNameTXT setReturnKeyType:UIReturnKeyNext];
.....
[self.emailTXT setReturnKeyType:UIReturnKeyDone];

// set text fields tags
[self.firstNameTXT setTag:0];
....// more text fields
[self.emailTXT setTag:5];

// add keyboard notification
[[NSNotificationCenter defaultCenter] addObserver:self     selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
}
[[NSNotificationCenter defaultCenter] addObserver:self      selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
}

// dismiss keyboard when tap outside text fields
- (IBAction)tapScreen:(UITapGestureRecognizer *)sender {
  if([self.firstNameTXT isFirstResponder])[self.firstNameTXT resignFirstResponder];
  ...
  if([self.emailTXT isFirstResponder])[self.emailTXT  resignFirstResponder];

  }
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
   if(textField.returnKeyType==UIReturnKeyNext) {
     // find the text field with next tag
     UIView *next = [[textField superview] viewWithTag:textField.tag+1];
     [next becomeFirstResponder];
   } else if (textField.returnKeyType==UIReturnKeyDone || textField.returnKeyType==UIReturnKeyDefault) {
    [textField resignFirstResponder];
 }
return YES;
}

// Moving current text field above keyboard
-(BOOL) textFieldShouldBeginEditing:(UITextField*)textField{
   CGRect viewFrame = self.view.frame;
   CGRect textFieldRect = [self.view.window convertRect:textField.bounds fromView:textField];
   CGRect viewRect = [self.view.window convertRect:self.view.bounds fromView:self.view];
   CGFloat textFieldBottomLine = textFieldRect.origin.y + textFieldRect.size.height + LITTLE_SPACE;//

   CGFloat keyboardHeight = keyboardSize.height;

   BOOL isTextFieldHidden = textFieldBottomLine > (viewRect.size.height - keyboardHeight)? TRUE :FALSE;
  if (isTextFieldHidden) {
    animatedDistance = textFieldBottomLine - (viewRect.size.height - keyboardHeight) ;
    viewFrame.origin.y -= animatedDistance;
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:ANIMATION_DURATION];
    [self.view setFrame:viewFrame];
    [UIView commitAnimations];
  }
  return YES;
}

-(void) restoreViewFrameOrigionYToZero{
  CGRect viewFrame = self.view.frame;
  if (viewFrame.origin.y != 0) {
    viewFrame.origin.y = 0;
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:ANIMATION_DURATION];
    [self.view setFrame:viewFrame];
    [UIView commitAnimations];
  }
}

-(void)keyboardDidShow:(NSNotification*)aNotification{
   NSDictionary* info = [aNotification userInfo];
   keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
 }

-(void)keyboardDidHide:(NSNotification*)aNotification{
   [self restoreViewFrameOrigionYToZero];// keyboard is dismissed, restore frame view to its  zero origin
}
@end

0

La réponse de @ mixca est très utile mais que faire si j'ai quelque chose de différent de UITextField. Je pense que la meilleure façon de le gérer en recherchant toutes les sous-vues de la vue principale avec la fonction récursive, consultez l'exemple ci-dessous

- (BOOL)findAndResignFirstResponder {
if (self.isFirstResponder) {
    [self resignFirstResponder];
    return YES;
}

    for (UIView *subView in self.subviews) {
        if ([subView findAndResignFirstResponder]) {
            return YES;
        }
    }
    return NO;
}

et vous pouvez également mettre cette méthode dans votre classe d'utilité et utiliser un geste de pression comme la réponse de @ mixca.


0

Swift 4 / 4,2 / 5

Vous pouvez également fermer le clavier lorsqu'une cellule est tapée - avant de faire quoi que ce soit d'autre.

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    view.endEditing(true)
    // Do something here
    }

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.