UITapGestureRecognizer - solo toque y doble toque

156

Estoy tratando de agregar 2 UITapGestureRecognizersa una vista, una para un solo toque y otra para eventos de doble toque. El reconocedor de un solo toque funciona como se espera (por sí solo). Pero parece que no puedo hacer funcionar el reconocedor de doble toque.

Han tratado de experimentar con propiedades como: cancelsTouchesInView, delaysTouchesBegany delaysTouchesEndedpero aún no funciona.

Cuando toco dos veces, el reconocedor de un solo toque siempre se activará y el evento de doble toque también se enviaría a la vista super. Pero el reconocedor de doble toque personalizado no parece ser notificado en absoluto.

Las documentaciones parecen sugerir que las 3 propiedades mencionadas anteriormente podrían usarse para este propósito. Pero no estoy seguro de qué valores deben establecerse y en qué reconocedor (s), simple, doble o ambos. Espero que alguien familiarizado con esto pueda ayudar.

El siguiente es el último bloque de código actualizado.

// ****** 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
fuente
30
Comentario aleatorio: los guiones bajos en los nombres de las variables harán que la mayoría de los programadores de Objective-C se avergüencen. Lo peor es que los nombres de sus variables no son descriptivos. ¿Por qué no usar singleTapRecognizer y doubleTapRecognizer (o algo similar)? Tarda una fracción de segundo más en escribir, pero hace que su código sea infinitamente más legible.
UIAdam
Gracias por el consejo, de acuerdo con usted en que los nombres de las variables deberían ser más descriptivos. Pero este segmento de código en particular no se ha finalizado y publicará un código más pulido y descriptivo como se sugiere ...
Stanley
En caso de que alguien más tenga un problema similar. Luché para que los reconocedores de doble toque y un solo toque funcionaran juntos de manera rápida (un solo toque funcionaba bien, pero no un doble toque). Arrastré los reconocedores a la escena usando el guión gráfico. Tenía los controladores y la declaración: singleTapRecognizer.requireGestureRecognizerToFail (doubleTabRecognizer) dentro de mi viewDidLoad, pero aún no hay doble toque. La pieza que faltaba del rompecabezas era arrastrar el ícono de reconocimiento de doble toque (desde la fila superior de la escena) sobre la parte de la vista donde debía reconocerse el doble toque.
Paulus
1
@UIAdam usar un guión bajo para prefijar un nombre privado de ivar en objc es bastante común, ¿pero no? (viniendo de un fondo rápido)
Charlton Provatas

Respuestas:

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: Si lo está utilizando numberOfTouchesRequired , debe ser .numberOfTouchesRequired = 1;

Para 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
fuente
Gracias por la respuesta, he probado tu código pero aún no funciona. Todavía debe haber algo que me haya perdido. ¿Tienes alguna pista más?
Stanley
¿Puedo tener su archivo de implementación para esto?
Anil Kothari
@Stanley: la respuesta de Anils debería funcionar, por supuesto, también debe proporcionar controladores (doSingleTap, doDoubleTap)
Rok Jarc
El solo toque actualiza un UITableView que funciona como se esperaba. El doble toque, por el momento, solo genera una declaración de registro utilizando NSLog. Mi sospecha es que el estado del primer respondedor va de la vista UIView a otro lugar después del primer toque, ya que no he hecho nada explícitamente sobre la cadena de respuesta.
Stanley
66
La solución me funciona. El selector de un solo toque se dispara después de algún retraso.
Vladimir Obrizan
47

Solución 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)

En la línea de código singleTap.require (toFail: doubleTap) estamos obligando al toque único a esperar y asegurarnos de que el evento de toque no sea un doble toque.

Surya Kameswara Rao Ravi
fuente
31

Debe utilizar el método requireGestureRecognizerToFail: Algo como esto:

[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];

UIAdam
fuente
Intenté utilizar el método "Fail" en ambos reconocedores justo ahora de nuevo. Pero aún no funciona. Si ya ha funcionado el doble toque antes, comparta un poco más de su experiencia conmigo.
Stanley
1
He intentado este código exacto (igual que lo que Anil ha publicado con más detalle) y funciona para mí.
UIAdam,
Gracias por el comentario, entonces hay todavía deben ser algo que me había perdido por mi parte ...
Stanley
Su código todavía se mete con retrasos Toques y otras cosas. Haz que siga exactamente el código de Anil. Solo use requireGestureRecognizerToFail una vez como lo tenemos.
UIAdam
Haré lo que me aconsejaste más tarde hoy o mañana, ya que me estoy quedando sin tiempo por el momento. Gracias por su amable asistencia ...
Stanley
15

// ---- en primer lugar tienes que asignar el gesto de toque doble y simple ------- //

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

// ----------------------- número de tomas ---------------- //

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

// ------- agregue doble toque y gesto de un solo toque en la vista o botón -------- //

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

No estoy seguro de si eso es exactamente lo que estás buscando, pero hice toques simples / dobles sin reconocedores de gestos. Lo estoy usando en UITableView, así que usé ese código en el método 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;

Los métodos singleTap y doubleTap son nulos con NSIndexPath como parámetro:

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

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

Espero eso ayude

Novarg
fuente
Gracias por la respuesta, @Novarg. ¿Tuviste el problema que tengo sobre los reconocedores doubleTap?
Stanley
@ Stanley no, el SingleTap está esperando 0.2 segundos antes de disparar. Y si mientras tanto se activó el segundo toque, entonces se cancela el método SingleTap.
Novarg
Se ve muy prometedor, gracias por su ayuda. Hoy me estoy quedando sin tiempo. Sin duda lo intentaré mañana :)
Stanley
Respuesta creativa;)
Michael
Muy buena solución. Solo necesitaba agregar tapCount = 0 en cada controlador (singleTap, doubleTap) para asegurarme de que también se reconocen los siguientes toques.
Sirio
3

Solución para 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)
límite
fuente
1

Implementé métodos UIGestureRecognizerDelegate para detectar singleTap y doubleTap.

Solo haz esto.

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

Luego implemente estos métodos delegados.

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

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

Algunas vistas tienen sus propios reconocedores de doble toque integrados ( MKMapViewsiendo un ejemplo). Para evitar esto, deberá implementar el UIGestureRecognizerDelegatemétodo shouldRecognizeSimultaneouslyWithGestureRecognizery devolver YES:

Primero implemente sus reconocedores dobles y simples:

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

Y luego implementar:

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

En referencia al comentario de @ stanley:

No intente usar gestos de toque para seleccionar las filas para trabajar UITableView, ya que ya tiene un manejo completo del toque ...

Pero debe establecer 'Cancela los toques en la vista' en 'NO' en sus reconocedores de gestos de toque único o nunca obtendrá los eventos de toque.

Oliver Dungey
fuente