UITapGestureRecognizer - tocco singolo e doppio tocco


156

Sto provando ad aggiungere 2 UITapGestureRecognizersa una vista, una per singolo tocco e una per eventi doppio tocco. Il riconoscitore a singolo tocco funziona come previsto (da solo). Ma non riesco a far funzionare il riconoscimento doppio tocco.

Hanno cercato di sperimentare con immobili come: cancelsTouchesInView, delaysTouchesBegane delaysTouchesEndedma non fa ancora lavoro.

Quando tocco due volte, il riconoscimento del tocco singolo viene sempre attivato e anche l'evento doppio tocco viene inviato alla super vista. Ma il riconoscimento doppio tocco personalizzato non sembra essere affatto notificato.

La documentazione sembra suggerire che le 3 proprietà sopra menzionate potrebbero essere utilizzate allo scopo. Ma non sono sicuro di quali valori debbano essere impostati e su quali riconoscitori (singoli, doppi o entrambi). Spero che qualcuno che abbia familiarità con questo possa aiutare.

Quello che segue è l'ultimo blocco di codice aggiornato.

// ****** 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
{

}

30
Commento casuale: i trattini bassi nei nomi delle variabili faranno rabbrividire la maggior parte dei programmatori di Objective-C. Quel che è peggio è che i nomi delle variabili non sono descrittivi. Perché non usare solo singleTapRecognizer e doubleTapRecognizer (o qualcosa di simile)? Ci vuole una frazione di secondo in più per scrivere, ma rende il codice infinitamente più leggibile.
UIAdam,

Grazie per il consiglio, d'accordo con te che i nomi delle variabili dovrebbero essere più descrittivi. Ma questo particolare segmento di codice non è stato finalizzato e pubblicherà un codice più raffinato e descrittivo come suggerito ...
Stanley

Nel caso in cui qualcun altro abbia un problema simile. Ho faticato a far sì che i riconoscitori di doppio tocco e tocco singolo funzionassero insieme rapidamente (il tocco singolo funzionava bene, ma nessun doppio tocco). Ho trascinato i riconoscitori sulla scena usando lo storyboard. Avevo i gestori e la dichiarazione: singleTapRecognizer.requireGestureRecognizerToFail (doubleTabRecognizer) all'interno del mio viewDidLoad, ma ancora nessun doppio tocco. Il pezzo mancante del puzzle era trascinare l'icona del riconoscimento del doppio tocco (dalla riga superiore della scena) sulla parte della vista in cui doveva essere riconosciuto il doppio tocco.
Paolo

1
@UIAdam che usa un carattere di sottolineatura per aggiungere un prefisso al nome di un ivar privato in objc è abbastanza comune anche se no? (proveniente da un rapido background)
Charlton Provatas il

Risposte:


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];

Nota: se lo stai usando numberOfTouchesRequired , deve esserlo .numberOfTouchesRequired = 1;

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

Grazie per la risposta, ho provato il tuo codice ma non funziona ancora. Dev'esserci ancora qualcosa che mi mancava. Hai altri suggerimenti?
Stanley,

posso avere il tuo file di implementazione per questo?
Anil Kothari,

@Stanley: la risposta di Anils dovrebbe funzionare, ovviamente devi anche fornire i gestori (doSingleTap, doDoubleTap)
Rok Jarc

Il singolo tocco aggiorna un UITableView che funziona come previsto. Il doppio tocco, per il momento, ha appena emesso un'istruzione di registro usando NSLog. Il mio sospetto è che lo stato del primo risponditore passi dall'UIView a un altro punto dopo il primo tocco poiché non ho fatto nulla di esplicito sulla catena di risposta.
Stanley,

6
La soluzione funziona per me. Il selettore a singolo tocco viene attivato dopo qualche ritardo.
Vladimir Obrizan,

47

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

Nella riga di codice singleTap.require (toFail: doubleTap) forziamo l'attesa del singolo tocco e assicuriamo che l'evento del tocco non sia un doppio tocco.


31

È necessario utilizzare il metodo requireGestureRecognizerToFail:. Qualcosa come questo:

[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];


Ho provato a usare di nuovo il metodo "Fail" con entrambi i riconoscitori. Ma ancora non funziona. Se hai già funzionato il doppio tocco, per favore condividi un po 'più della tua esperienza con me.
Stanley,

1
Ho provato questo codice esatto (lo stesso di quello che Anil ha pubblicato in modo più dettagliato) e funziona per me.
UIAdam,

Grazie per il commento, quindi ci deve essere ancora qualcosa che mi ero perso da parte mia ...
Stanley

Il tuo codice continua a pasticciare con ritardi Touch e quant'altro. Fallo in modo che segua esattamente il codice di Anil. Utilizzare unidireGestureRecognizerToFail solo una volta nel modo in cui l'abbiamo.
UIAdam,

Farà come mi hai consigliato più tardi, oggi o domani, perché sto esaurendo il tempo per il momento. Grazie per la cortese assistenza ...
Stanley,

15

// ---- in primo luogo devi assegnare il gesto del doppio e del singolo tocco ------- //

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];

// ----------------------- numero di tocchi ---------------- //

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

// ------- aggiungi il doppio tocco e il gesto del singolo tocco sulla vista o sul pulsante -------- //

[self.view addGestureRecognizer : doubleTap];
[self.view addGestureRecognizer : singleTap];

10

Non sono sicuro che sia esattamente quello che stai cercando, ma ho fatto tocchi singoli / doppi senza riconoscimento dei gesti. Lo sto usando in un UITableView, quindi ho usato quel codice nel metodo 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;

I metodi singleTap e doubleTap sono semplicemente nulli con NSIndexPath come parametro:

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

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

Spero che sia d'aiuto


Grazie per la risposta, @Novarg. Hai avuto il problema che sto riscontrando sui riconoscitori doubleTap?
Stanley,

@ Stanley no, singleTap attende 0,2 secondi prima di sparare. E se nel frattempo è stato attivato il secondo tocco, il metodo singleTap viene annullato.
Novarg,

Sembra molto promettente, grazie per il tuo aiuto. Sono di nuovo a corto di tempo oggi. Ci proverò sicuramente domani :)
Stanley,

Risposta creativa;)
Michael

ottima soluzione. Ho solo bisogno di aggiungere tapCount = 0 su ciascun gestore (singleTap, doubleTap) per essere sicuro che anche i seguenti tocchi siano riconosciuti.
Sirio,

3

Soluzione per 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)

1

Ho implementato i metodi UIGestureRecognizerDelegate per rilevare sia singleTap che doubleTap.

Fallo e basta.

 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];

Quindi implementare questi metodi delegati.

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

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
    return YES;
}

0

Alcune viste hanno i propri riconoscitori di doppio tocco integrati (a MKMapViewtitolo di esempio). Per aggirare il problema dovrai implementare il UIGestureRecognizerDelegatemetodo shouldRecognizeSimultaneouslyWithGestureRecognizere restituire YES:

Per prima cosa implementa i tuoi riconoscitori doppi e singoli:

// 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];

E quindi implementare:

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

-1

In riferimento al commento di @ stanley -

Non provare a usare i gesti dei tocchi per remare le selezioni in cui lavorare UITableViewpoiché ha già la gestione completa dei tocchi ....

Ma è necessario impostare "Annulla tocchi in vista" su "NO" sui riconoscitori dei gesti a tocco singolo, altrimenti non verranno mai visualizzati gli eventi di tocco.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.