¿Cómo puedo detectar un doble toque en una celda determinada en UITableView?

¿Cómo puedo detectar un doble toque en una celda determinada en UITableView ?

es decir, ¿quiero realizar una acción si el usuario hizo un solo toque y otro si el usuario hizo un doble toque? También necesito saber una ruta de índice donde se realizó el toque.

¿Cómo puedo lograr este objective?

Gracias.

Si no desea crear una subclase de UITableView , use un temporizador con didSelectRowAtIndex: la vista de didSelectRowAtIndex:

 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { //checking for double taps here if(tapCount == 1 && tapTimer != nil && tappedRow == indexPath.row){ //double tap - Put your double tap code here [tapTimer invalidate]; [self setTapTimer:nil]; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Double Tap" message:@"You double-tapped the row" delegate:self cancelButtonTitle:nil otherButtonTitles:@"OK", nil]; [alert show]; [alert release]; } else if(tapCount == 0){ //This is the first tap. If there is no tap till tapTimer is fired, it is a single tap tapCount = tapCount + 1; tappedRow = indexPath.row; [self setTapTimer:[NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(tapTimerFired:) userInfo:nil repeats:NO]]; } else if(tappedRow != indexPath.row){ //tap on new row tapCount = 0; if(tapTimer != nil){ [tapTimer invalidate]; [self setTapTimer:nil]; } } } - (void)tapTimerFired:(NSTimer *)aTimer{ //timer fired, there was a single tap on indexPath.row = tappedRow if(tapTimer != nil){ tapCount = 0; tappedRow = -1; } } 

HTH

Anular en su clase UITableView este método

 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { if(((UITouch *)[touches anyObject]).tapCount == 2) { NSLog(@"DOUBLE TOUCH"); } [super touchesEnded:touches withEvent:event]; } 

En su subclase UITableView , haga algo como esto:

 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { for (UITouch* touch in touches) { if (touch.tapCount == 2) { CGPoint where = [touch locationInView:self]; NSIndexPath* ip = [self indexPathForRowAtPoint:where]; NSLog(@"double clicked index path: %@", ip); // do something useful with index path 'ip' } } [super touchesEnded:touches withEvent:event]; } 

Primero defina:

 int tapCount; NSIndexPath *tableSelection; 

como variables de nivel de clase en el archivo .h y realice toda la configuración necesaria. Entonces…

 - (void)tableView(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { tableSelection = indexPath; tapCount++; switch (tapCount) { case 1: //single tap [self performSelector:@selector(singleTap) withObject: nil afterDelay: .4]; break; case 2: //double tap [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(singleTap) object:nil]; [self performSelector:@selector(doubleTap) withObject: nil]; break; default: break; } } #pragma mark - #pragma mark Table Tap/multiTap - (void)singleTap { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Alert" message:@"Single tap detected" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; tapCount = 0; } - (void)doubleTap { NSUInteger row = [tableSelection row]; companyName = [self.suppliers objectAtIndex:row]; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Alert" message:@"DoubleTap" delegate:nil cancelButtonTitle:@"Yes" otherButtonTitles: nil]; [alert show]; tapCount = 0; } 
 if([touch tapCount] == 1) { [self performSelector:@selector(singleTapRecevied) withObject:self afterDelay:0.3]; } else if ([touch tapCount] == 2) { [TapEnableImageView cancelPreviousPerformRequestsWithTarget:self selector:@selector(singleTapRecevied) object:self]; } 

Use el selector de rendimiento para llamar a un selector en lugar de usar un temporizador. Esto resuelve el problema mencionado por @ V1ru8.

Elegí implementarlo anulando el UITableViewCell .

MyTableViewCell.h

 @interface MyTableViewCell : UITableViewCell @property (nonatomic, assign) int numberOfClicks; @end 

MyTableViewCell.m

 @implementation MyTableViewCell - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *aTouch = [touches anyObject]; self.numberOfClicks = [aTouch tapCount]; [super touchesEnded:touches withEvent:event]; } 

TableViewController.m

 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { MyTableViewCell *myCell = (MyTableViewCell*) [self.tableView cellForRowAtIndexPath:indexPath]; NSLog(@"clicks:%d", myCell.numberOfClicks); if (myCell.numberOfClicks == 2) { NSLog(@"Double clicked"); } } 

Otra respuesta

 int touches; - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { touches++; if(touches==2){ //your action } } - (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath { touches=0; } 

Probablemente necesite subclasificar UITableView y anular los eventos táctiles que sean apropiados ( touchesBegan:withEvent ;, touchesEnded:withEvent , etc.). Inspeccione los eventos para ver cuántos toques hubo y realice su comportamiento personalizado. No olvides llamar a UITableView's métodos táctiles UITableView's , de lo contrario no obtendrás el comportamiento predeterminado.

De acuerdo con @lostInTransit preparé el código en Swift

 var tapCount:Int = 0 var tapTimer:NSTimer? var tappedRow:Int? override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { //checking for double taps here if(tapCount == 1 && tapTimer != nil && tappedRow == indexPath.row){ //double tap - Put your double tap code here tapTimer?.invalidate() tapTimer = nil } else if(tapCount == 0){ //This is the first tap. If there is no tap till tapTimer is fired, it is a single tap tapCount = tapCount + 1; tappedRow = indexPath.row; tapTimer = NSTimer.scheduledTimerWithTimeInterval(0.2, target: self, selector: "tapTimerFired:", userInfo: nil, repeats: false) } else if(tappedRow != indexPath.row){ //tap on new row tapCount = 0; if(tapTimer != nil){ tapTimer?.invalidate() tapTimer = nil } } } func tapTimerFired(aTimer:NSTimer){ //timer fired, there was a single tap on indexPath.row = tappedRow if(tapTimer != nil){ tapCount = 0; tappedRow = -1; } } 

Nota: por favor, vea los comentarios a continuación para ver si bien esta solución funcionó para mí, aún así puede que no sea una buena idea.

Una alternativa para crear una subclase de UITableView o UITableViewCell (y usar un temporizador) sería simplemente extender la clase UITableViewCell con una categoría, por ejemplo (usando la respuesta de @ oxigen, en este caso para la celda en lugar de la tabla):

 @implementation UITableViewCell (DoubleTap) - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { if(((UITouch *)[touches anyObject]).tapCount == 2) { NSLog(@"DOUBLE TOUCH"); } [super touchesEnded:touches withEvent:event]; } @end 

De esta forma, no es necesario cambiar el nombre de las instancias existentes de UITableViewCell con el nuevo nombre de clase (extenderá todas las instancias de la clase).

Tenga en cuenta que ahora super en este caso (esta es una categoría) no se refiere a UITableView sino a su super, UITView . Pero la llamada real al método touchesEnded:withEvent: está en UIResponder (de los cuales tanto UITView como UITableViewCell son subclases), por lo que no hay diferencia.

Aquí está mi solución completa:

CustomTableView.h

 // // CustomTableView.h // #import  @interface CustomTableView : UITableView // Nothing needed here @end 

CustomTableView.m

 // // CustomTableView.m // #import "CustomTableView.h" @implementation CustomTableView // // Touch event ended // - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { // For each event received for (UITouch * touch in touches) { NSIndexPath * indexPath = [self indexPathForRowAtPoint: [touch locationInView:self] ]; // One tap happened if([touch tapCount] == 1) { // Call the single tap method after a delay [self performSelector: @selector(singleTapReceived:) withObject: indexPath afterDelay: 0.3]; } // Two taps happened else if ([touch tapCount] == 2) { // Cancel the delayed call to the single tap method [NSObject cancelPreviousPerformRequestsWithTarget: self selector: @selector(singleTapReceived:) object: indexPath ]; // Call the double tap method instead [self performSelector: @selector(doubleTapReceived:) withObject: indexPath ]; } } // Pass the event to super [super touchesEnded: touches withEvent: event]; } // // Single Tap // -(void) singleTapReceived:(NSIndexPath *) indexPath { NSLog(@"singleTapReceived - row: %ld",(long)indexPath.row); } // // Double Tap // -(void) doubleTapReceived:(NSIndexPath *) indexPath { NSLog(@"doubleTapReceived - row: %ld",(long)indexPath.row); } @end 

Mejora para la respuesta de oxigeno .

 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; if(touch.tapCount == 2) { CGPoint touchPoint = [touch locationInView:self]; NSIndexPath *touchIndex = [self indexPathForRowAtPoint:touchPoint]; if (touchIndex) { // Call some callback function and pass 'touchIndex'. } } [super touchesEnded:touches withEvent:event]; } 

Swift 3 solución de comparar respuestas. No necesita extensiones, simplemente agregue este código.

 override func viewDidLoad() { viewDidLoad() let doubleTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap(sender:))) doubleTapGestureRecognizer.numberOfTapsRequired = 2 tableView.addGestureRecognizer(doubleTapGestureRecognizer) let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTapGesture(sender:))) tapGestureRecognizer.numberOfTapsRequired = 1 tapGestureRecognizer.require(toFail: doubleTapGestureRecognizer) tableView.addGestureRecognizer(tapGestureRecognizer) } func handleTapGesture(sender: UITapGestureRecognizer) { let touchPoint = sender.location(in: tableView) if let indexPath = tableView.indexPathForRow(at: touchPoint) { print(indexPath) } } func handleDoubleTap(sender: UITapGestureRecognizer) { let touchPoint = sender.location(in: tableView) if let indexPath = tableView.indexPathForRow(at: touchPoint) { print(indexPath) } } 

Esta solución solo funciona para UICollectionView o la celda de UITableView.

Primero declara estas variables

int number_of_clicks;

BOOL thread_started;

A continuación, coloque este código en su didSelectItemAtIndexPath

 ++number_of_clicks; if (!thread_started) { thread_started = YES; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.25 * NSEC_PER_SEC), dispatch_get_main_queue(),^{ if (number_of_clicks == 1) { ATLog(@"ONE"); }else if(number_of_clicks == 2){ ATLog(@"DOUBLE"); } number_of_clicks = 0; thread_started = NO; }); } 

0.25 es la demora de entre 2 clics. Creo que 0.25 es perfecto para detectar este tipo de clic. Ahora puede detectar solo un clic y dos clics por separado. Buena suerte