Double tap a table view cell on a UITableViewController

So I have one of those nifty UITableViewController views in my application, and since the app is now starting to get a bit more complex, I wanted to have a quick way to be able to do multiple things with a cell from that view.  Unfortunately, if you use the UITableViewCellStyleDefault style to create your cell, there is not much you can do with it, other than to have an accessory type.  This is how I started using the cells, allowing the user to set a cell to be selected or not selected (setting the cell accessoryType to UITableViewCellAccessoryCheckmark or UITableViewCellAccessoryNone).

In order to perform a different function on the cell, I figured that it couldn’t be too hard to allow the user to double tap the cell to do something other than turn the check mark off and on again or vice versa.  As per usual with the iPhone platform, it took a bit of digging.

At first, I thought I could use a UIGestureRecognizer to detect the double tap.  Unfortunately, our apps are still trying to support 3.1.3 OS users, and the UIGestureRecognizer requires 3.2.

So with a bit more digging, I found a solution on Stack Overflow that I “borrowed”.  Unfortunately, that code was a bit rough and required some minor tweaks and fixes, so here below is how to do this.

First, you need to make sure to add the necessary ivars to your class header file:

int tapCount, tappedRow, doubleTapRow;

Then, here is the code that you will need in your implementation file.  Those of you familiar with the UITableViewDelegate will see something familiar and something to extend it.

#pragma mark -
#pragma mark Table view delegate
 
- (void)tapTimerFired:(NSTimer *)aTimer
{
    // timer fired, there was a single tap on indexPath.row = tappedRow
 
    // do something here with tappedRow
 
    [cell setSelected:NO animated:YES];  // maybe, maybe not
 
    if (tapTimer != nil)
    {
        tapCount = 0;
        tappedRow = -1;
    }
}
 
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
 
    // 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;
 
        //NSLog(@"double tapped the cell");
        doubleTapRow = tappedRow;
 
        [cell setSelected:NO animated:YES];  // maybe, maybe not
 
        // do something here with doubleTapRow
 
        tapCount = 0;
        tappedRow = -1;
    }
    else if (tapCount == 0)
    {
        // This is the first tap. If there is no tap till tapTimer is fired, it is a single tap
        tapCount = 1;
        tappedRow = indexPath.row;
        tapTimer = [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];
            tapTimer = nil;
        }
    }
}

As it says in the code, you may or may not want to turn off the cell selection, it is up to you whether you need to do that or not. Also, you may want to play around with the time factor where the tapTimer is created if it does not work as well as you would like.

3 Comments

  1. BP says:

    That is just what I was going for.

  2. ZC says:

    This only works with single-section tables. If you wanted to support multiple sections you can convert tappedRow to an NSIndexPath *tappedIndexPath property.

Leave a Reply