Come posso rilevare un doppio touch su una determinata cella in UITableView?

Come posso rilevare un doppio touch su una determinata cella in UITableView ?

cioè voglio eseguire un’azione se l’utente ha effettuato un singolo touch e un altro se un utente ha fatto un doppio touch? Devo anche conoscere un percorso indice in cui è stato effettuato il touch.

Come posso raggiungere questo objective?

Grazie.

Se non si desidera creare una sottoclass di UITableView , utilizzare un timer con didSelectRowAtIndex: della vista tabella 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

Sovrascrivi questo metodo nella class UITableView

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

Nella sottoclass UITableView , fai qualcosa di simile a questo:

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

Prima definizione:

 int tapCount; NSIndexPath *tableSelection; 

come variabili di livello di class nel file .h e fai tutte le impostazioni necessarie. Poi…

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

Usa performSelector per chiamare un selettore invece di usare un timer. Questo risolve il problema menzionato da @ V1ru8.

Ho scelto di implementarlo sovrascrivendo 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"); } } 

Un’altra risposta

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

Probabilmente avrai bisogno di sottoclass UITableView e di sovrascrivere qualsiasi evento tattile appropriato ( touchesBegan:withEvent ;, touchesEnded:withEvent , ecc.) Controlla gli eventi per vedere quanti tocchi ci sono stati e fai il tuo comportamento personalizzato. Non dimenticare di chiamare UITableView's metodi tattili UITableView's , altrimenti non otterrai il comportamento predefinito.

Secondo @lostInTransit ho preparato il codice in 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: si prega di vedere i commenti qui sotto per vedere se mentre questa soluzione ha funzionato per me, potrebbe ancora non essere una buona idea.

Un’alternativa alla creazione di una sottoclass di UITableView o UITableViewCell (e di usare un timer) sarebbe solo quella di estendere la class UITableViewCell con una categoria, ad esempio (usando la risposta di @ oxigen, in questo caso per la cella invece della tabella):

 @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 

In questo modo non devi andare in giro a rinominare le istanze esistenti di UITableViewCell con il nuovo nome di class (estenderà tutte le istanze della class).

Nota che ora super in questo caso (essendo una categoria) non si riferisce a UITableView ma al suo super, UITView . Ma la chiamata al metodo effettivo per touchesEnded:withEvent: è in UIResponder (di cui sia UITView che UITableViewCell sono sottoclassi), quindi non c’è differenza.

Ecco la mia soluzione 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 

Miglioramento della risposta dell’ossigeno .

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

Soluzione Swift 3 da confrontare le risposte. Non sono necessarie estensioni, basta aggiungere questo codice.

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

Questa soluzione funziona solo per UICollectionView o la cella di UITableView.

Prima dichiarare queste variabili

int number_of_clicks;

BOOL thread_started;

Quindi inserisci questo codice nel 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 è il ritardo tra 2 clic. Penso che 0.25 sia perfetto per rilevare questo tipo di clic. Ora è ansible rilevare solo un clic e due clic separatamente. In bocca al lupo