UITapGestureRecognizer - touche simple et double pression

156

J'essaie d'en ajouter 2 UITapGestureRecognizersà une vue, une pour les événements à pression unique et une pour les événements à double pression. Le module de reconnaissance de pression unique fonctionne comme prévu (seul). Mais je ne semble pas être en mesure de faire fonctionner le module de reconnaissance du double tap.

Ont essayé d'expérimenter avec des propriétés telles que : cancelsTouchesInView, delaysTouchesBeganet delaysTouchesEndedmais ne fonctionne toujours pas.

Lorsque je touche deux fois, la reconnaissance de pression unique est toujours activée et l'événement de double pression est également envoyé à la super vue. Mais le module de reconnaissance personnalisé du double tap ne semble pas du tout être notifié.

Les documentations semblent suggérer que les 3 propriétés mentionnées ci-dessus pourraient être utilisées à cette fin. Mais je ne suis tout simplement pas sûr des valeurs à définir et sur quel (s) module de reconnaissance (simple, double ou les deux). J'espère que quelqu'un familier avec cela pourra vous aider.

Ce qui suit est le dernier bloc de code mis à jour.

// ****** gesture recognizers ******

- (void)addSingleAndDoubleTapGestureRecognizersToView:(UIView *)view
{
    // single tap    
    UITapGestureRecognizer *singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget: tableViewController action: @selector(handleSingleTapOnView:)];                                 
    [singleTapRecognizer setNumberOfTouchesRequired:1];
    [view addGestureRecognizer: singleTapRecognizer];

    // double tap 
    UITapGestureRecognizer *doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget: tableViewController action: @selector (handleDoubleTapOnView:)];        
    [doubleTapRecognizer setNumberOfTouchesRequired:2];         
    [singleTapRecognizer requireGestureRecognizerToFail: doubleTapRecognizer];
    [view addGestureRecognizer: doubleTapRecognizer];         
}

- (void)handleSingleTapOnView:(id)sender
{

}

- (void)handleDoubleTapOnView:(id)sender
{

}
Stanley
la source
30
Commentaire aléatoire: les traits de soulignement dans les noms de variables feront grincer des dents la plupart des programmeurs Objective-C. Le pire, c'est que vos noms de variables ne sont pas descriptifs. Pourquoi ne pas simplement utiliser singleTapRecognizer et doubleTapRecognizer (ou quelque chose de similaire)? Il faut une fraction de seconde de plus pour taper, mais rend votre code infiniment plus lisible.
UIAdam
Merci pour les conseils, convenez avec vous que les noms des variables devraient être plus descriptifs. Mais ce segment de code particulier n'a pas été finalisé et affichera un code plus précis et descriptif comme suggéré ...
Stanley
Au cas où quelqu'un d'autre aurait un problème similaire. J'ai eu du mal à faire en sorte que les reconnaisseurs de double tap et de simple tap fonctionnent ensemble rapidement (un simple tap fonctionnait bien, mais pas de double tap). J'ai fait glisser les outils de reconnaissance sur la scène à l'aide du storyboard. J'avais les gestionnaires et la déclaration: singleTapRecognizer.requireGestureRecognizerToFail (doubleTabRecognizer) dans mon viewDidLoad, mais toujours pas de double tap. Ma pièce manquante du puzzle était de faire glisser l'icône de reconnaissance du double tap (de la rangée supérieure de la scène) sur la partie de la vue où le double tap devait être reconnu.
Paulus
1
@UIAdam en utilisant un trait de soulignement pour préfixer un nom ivar privé dans objc est assez courant mais non? (venant d'un arrière-plan rapide)
Charlton Provatas

Réponses:

412
UITapGestureRecognizer *singleTap = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doSingleTap)] autorelease];
singleTap.numberOfTapsRequired = 1; 
[self.view addGestureRecognizer:singleTap];

UITapGestureRecognizer *doubleTap = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doDoubleTap)] autorelease];
doubleTap.numberOfTapsRequired = 2; 
[self.view addGestureRecognizer:doubleTap];

[singleTap requireGestureRecognizerToFail:doubleTap];

Remarque: si vous l'utilisez, numberOfTouchesRequired il doit être .numberOfTouchesRequired = 1;

Pour Swift

let singleTapGesture = UITapGestureRecognizer(target: self, action: #selector(didPressPartButton))
singleTapGesture.numberOfTapsRequired = 1
view.addGestureRecognizer(singleTapGesture)

let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(didDoubleTap))
doubleTapGesture.numberOfTapsRequired = 2
view.addGestureRecognizer(doubleTapGesture)

singleTapGesture.require(toFail: doubleTapGesture)
Anil Kothari
la source
Merci pour la réponse, j'ai essayé votre code mais il ne fonctionne toujours pas. Il devait encore y avoir quelque chose que j'avais manqué. Avez-vous un autre indice?
Stanley
puis-je avoir votre dossier d'implémentation pour cela?
Anil Kothari le
@Stanley: La réponse d'Anils devrait fonctionner, bien sûr, vous devez également fournir des gestionnaires (doSingleTap, doDoubleTap)
Rok Jarc
Le simple tap met à jour un UITableView qui fonctionne comme prévu. Le double tap, pour le moment, sort simplement une instruction de journal en utilisant NSLog. Je soupçonne que le statut de premier répondeur passe de l'UIView à un autre endroit après le premier tap car je n'ai rien fait explicitement sur la chaîne de réponse.
Stanley
6
La solution fonctionne pour moi. Le sélecteur de prise unique est déclenché après un certain délai.
Vladimir Obrizan le
47

Solution Swift 3:

let singleTap = UITapGestureRecognizer(target: self, action:#selector(self.singleTapAction(_:)))
singleTap.numberOfTapsRequired = 1
view.addGestureRecognizer(singleTap)

let doubleTap = UITapGestureRecognizer(target: self, action:#selector(self.doubleTapAction(_:)))
doubleTap.numberOfTapsRequired = 2
view.addGestureRecognizer(doubleTap)

singleTap.require(toFail: doubleTap)

Dans la ligne de code singleTap.require (toFail: doubleTap), nous forçons le simple tap à attendre et à nous assurer que l'événement tap n'est pas un double tap.

Surya Kameswara Rao Ravi
la source
31

Vous devez utiliser la méthode requireGestureRecognizerToFail :. Quelque chose comme ça:

[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];

UIAdam
la source
J'ai essayé d'utiliser la méthode "Fail" avec les deux outils de reconnaissance tout à l'heure. Mais ne fonctionne toujours pas. Si vous avez déjà réussi à utiliser le double tap, partagez un peu plus votre expérience avec moi.
Stanley
1
J'ai essayé ce code exact (identique à ce qu'Anil a publié plus en détail) et cela fonctionne pour moi.
UIAdam
Merci pour le commentaire, alors il doit encore y avoir quelque chose que j'avais manqué de ma part ...
Stanley
Votre code encombre toujours les retards, les touches et autres. Faites en sorte qu'il suive exactement le code d'Anil. N'utilisez requireGestureRecognizerToFail qu'une fois que nous l'avons.
UIAdam
Fera comme vous l'avez conseillé plus tard dans la journée ou demain, car je manque de temps pour le moment. Merci pour votre aimable assistance ...
Stanley
15

// ---- tout d'abord, vous devez allouer le geste double et simple tap ------- //

UITapGestureRecognizer* doubleTap = [[UITapGestureRecognizer alloc] initWithTarget : self action : @selector (handleDoubleTap:)];

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

[singleTap requireGestureRecognizerToFail : doubleTap];
[doubleTap setDelaysTouchesBegan : YES];
[singleTap setDelaysTouchesBegan : YES];

// ----------------------- nombre de tap ---------------- //

[doubleTap setNumberOfTapsRequired : 2];
[singleTap setNumberOfTapsRequired : 1];

// ------- ajouter un double tap et un simple geste sur la vue ou le bouton -------- //

[self.view addGestureRecognizer : doubleTap];
[self.view addGestureRecognizer : singleTap];
Jaspreet Singh
la source
10

Je ne sais pas si c'est exactement ce que vous recherchez, mais j'ai fait des tapotements simples / doubles sans reconnaissance de gestes. Je l'utilise dans un UITableView, j'ai donc utilisé ce code dans la méthode didSelectRowAtIndexPath

    tapCount++;
    switch (tapCount)
    {
        case 1: //single tap
            [self performSelector:@selector(singleTap:) withObject: indexPath afterDelay: 0.2];
            break;
        case 2: //double tap
            [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(singleTap:) object:indexPath];
            [self performSelector:@selector(doubleTap:) withObject: indexPath];
            break;
        default:
            break;
    }
    if (tapCount>2) tapCount=0;

Les méthodes singleTap et doubleTap sont simplement vides avec NSIndexPath comme paramètre:

- (void)singleTap:(NSIndexPath *)indexPath {
  //do your stuff for a single tap
}

- (void)doubleTap:(NSIndexPath *)indexPath {
  //do your stuff for a double tap
}

J'espère que ça aide

Novarg
la source
Merci pour la réponse, @Novarg. Avez-vous eu le problème que je rencontre avec les outils de reconnaissance doubleTap?
Stanley
@Stanley non, le singleTap attend 0,2 seconde avant de tirer. Et si entre-temps le deuxième tap a été activé, la méthode singleTap est annulée.
Novarg
Cela semble très prometteur, merci pour votre aide. Je manque encore de temps aujourd'hui. Je vais certainement essayer demain :)
Stanley
Réponse créative;)
Michael
très bonne solution. J'avais juste besoin d'ajouter tapCount = 0 sur chaque gestionnaire (singleTap, doubleTap) afin d'être sûr que les touches suivantes sont également reconnues.
Sirio
3

Solution pour Swift 2:

let singleTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleSingleTap))
singleTapGesture.numberOfTapsRequired = 1 // Optional for single tap
view.addGestureRecognizer(singleTapGesture)

let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap))
doubleTapGesture.numberOfTapsRequired = 2
view.addGestureRecognizer(doubleTapGesture)

singleTapGesture.requireGestureRecognizerToFail(doubleTapGesture)
limfinité
la source
1

J'ai implémenté les méthodes UIGestureRecognizerDelegate pour détecter à la fois singleTap et doubleTap.

Fais juste ça.

 UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleDoubleTapGesture:)];
    [doubleTap setDelegate:self];
    doubleTap.numberOfTapsRequired = 2;
    [self.headerView addGestureRecognizer:doubleTap];

    UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleSingleTapGesture:)];
    singleTap.numberOfTapsRequired = 1;
    [singleTap setDelegate:self];
    [doubleTap setDelaysTouchesBegan:YES];
    [singleTap setDelaysTouchesBegan:YES];
    [singleTap requireGestureRecognizerToFail:doubleTap];
    [self.headerView addGestureRecognizer:singleTap];

Ensuite, implémentez ces méthodes de délégation.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
    return  YES;
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
    return YES;
}
iPhoneDéveloppeur
la source
0

Certaines vues ont leurs propres outils de reconnaissance intégrés ( MKMapViewà titre d'exemple). Pour contourner cela, vous devrez implémenter la UIGestureRecognizerDelegateméthode shouldRecognizeSimultaneouslyWithGestureRecognizeret retourner YES:

Commencez par implémenter vos systèmes de reconnaissance double et simple:

// setup gesture recognizers
UITapGestureRecognizer* singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                                action:@selector(mapViewTapped:)];
singleTapRecognizer.delegate = self;
singleTapRecognizer.numberOfTapsRequired = 1;


UITapGestureRecognizer* doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                                      action:@selector(mapViewDoubleTapped:)];
doubleTapRecognizer.delegate = self;    // this allows
doubleTapRecognizer.numberOfTapsRequired = 2;
[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];

Et puis implémentez:

#pragma mark UIGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer
*)otherGestureRecognizer {  return YES; }
zerodog
la source
-1

En référence au commentaire de @ stanley -

N'essayez pas d'utiliser les gestes tactiles pour sélectionner les lignes dans lesquelles travailler, UITableViewcar il dispose déjà d'une gestion complète des pressions ....

Mais vous devez définir `` Annule les touches dans la vue '' sur `` NON '' sur vos outils de reconnaissance de gestes à pression unique, sinon il n'obtiendra jamais les événements de pression.

Oliver Dungey
la source