如何检测UITableView中某个单元格的双击?

时间:2009-06-23 08:09:30

标签: iphone cocoa-touch uitableview

如何检测UITableView中某个单元格的双击?

我想在用户单次触摸时执行一个操作,如果用户进行双击,我想执行另一个操作?我还需要知道触摸的索引路径。

我如何实现这一目标?

感谢。

14 个答案:

答案 0 :(得分:31)

如果您不想创建UITableView的子类,请使用具有表视图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

答案 1 :(得分:27)

UITableView类中覆盖此方法

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
 {

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

答案 2 :(得分:10)

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

答案 3 :(得分:9)

首先定义:

int tapCount;
NSIndexPath *tableSelection;

作为.h文件中的类级变量,并进行所有必要的设置。然后...

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

答案 4 :(得分:6)

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来调用选择器而不是使用计时器。这解决了@ V1ru8提到的问题。

答案 5 :(得分:6)

我选择通过覆盖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");
   }
}

答案 6 :(得分:2)

另一个答案

int touches;

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
  touches++;

    if(touches==2){
       //your action
    }
}

- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
    touches=0;
}

答案 7 :(得分:1)

您可能需要子类化UITableView并覆盖适当的触摸事件(touchesBegan:withEvent;,touchesEnded:withEvent等)。检查事件以查看有多少触摸,并做你的自定义行为。不要忘记拨打UITableView's触摸方法,否则您将无法获得默认行为。

答案 8 :(得分:1)

根据@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;
    }
}

答案 9 :(得分:1)

来自比较答案的Swift 3解决方案。无需任何扩展,只需添加此代码即可。

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

答案 10 :(得分:0)

注意:请看下面的评论,看看虽然这个解决方案对我有用,但它仍然可能不是一个好主意。

创建UITableViewUITableViewCell的子类(以及使用计时器)的另一种方法是将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(其中UITViewUITableViewCell都是子类),因此没有区别。

答案 11 :(得分:0)

这是我的完整解决方案:

<强> 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

答案 12 :(得分:0)

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

答案 13 :(得分:-1)

此解决方案仅适用于UICollectionView或UITableView的单元格。

首先声明这些变量

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是2次点击之间的延迟。我认为0.25非常适合检测这种类型的点击。现在,您只能检测到一次单击和两次单击。祝你好运