如何检测UITableView中的某个单元格上的双击?
如何检测UITableView
的某个单元格上的双击?
即如果用户做了一个单一的触摸,而另一个用户做了双重触摸,我想执行一个动作? 我也需要知道触摸的索引path。
我怎样才能达到这个目标?
谢谢。
如果您不想创buildUITableView
的子类,请使用具有表视图的didSelectRowAtIndex:
的计时器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
在你的UITableView
类中覆盖这个方法
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { if(((UITouch *)[touches anyObject]).tapCount == 2) { NSLog(@"DOUBLE TOUCH"); } [super touchesEnded:touches withEvent:event]; }
在你的UITableView
子类中,做这样的事情:
- (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]; }
首先定义:
int tapCount; NSIndexPath *tableSelection;
作为.h文件中的类级variables,并进行所有必要的设置。 然后…
- (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]; }
使用performSelector调用select器而不是使用定时器。 这解决了@ V1ru8提到的问题。
我select通过覆盖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"); } }
另一个答案
int touches; - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { touches++; if(touches==2){ //your action } } - (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath { touches=0; }
您可能需要touchesEnded:withEvent
UITableView
并覆盖任何适合的触摸事件( touchesBegan:withEvent
; touchesEnded:withEvent
等)。检查事件以查看有多less触摸,并执行您的自定义行为。 不要忘记调用UITableView's
触摸方法,否则你将不会得到默认的行为。
根据@lostInTransit我准备在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; } }
注意:请看下面的评论,看看虽然这个解决scheme为我工作,但它可能不是一个好主意。
创buildUITableView
或UITableViewCell
(以及使用计时器)的子类的一个替代方法就是扩展UITableViewCell
类,例如(在本例中使用@ oxigen的答案,而不是表格):
@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
这样你就不必重新命名UITableViewCell
现有实例,并使用新的类名(将扩展该类的所有实例)。
请注意,现在super
在这种情况下(这是一个类别)不引用UITableView
但它的超级, UITView
。 但实际的方法调用touchesEnded:withEvent:
在UIResponder
(其中UITView
和UITableViewCell
都是子类),所以没有什么区别。
这是我完整的解决scheme:
CustomTableView.h
// // CustomTableView.h // #import <UIKit/UIKit.h> @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
改进oxigen答案。
- (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解决scheme比较答案。 不需要任何扩展,只需添加此代码。
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) } }
此解决scheme仅适用于UICollectionView或UITableView的单元格。
首先声明这些variables
int number_of_clicks;
BOOL thread_started;
然后把这个代码放在你的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是两次点击之间的延迟。 我认为0.25是完美的检测这种types的点击。 现在,您只能单独检测一次点击和两次点击。 祝你好运