Dranix
Dranix

Reputation: 551

iOS - indexPathForRowAtPoint don't return correct indexPath with different cell height

I have UITableView that contains many cell. User can expand cell to see more content in this cell by push the expand button in this cell (only 1 cell can expand at time):

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if(selectedRowIndex == indexPath.row) return 205;
    else return 60;
}

In the storyboard, I drag UILongPressGesture into cell button and named it longPress (cell is custom, it has 2 buttons in it, 1 need to recognize LongPressGesture, the other expand cell height):

@property (retain, nonatomic) IBOutlet UILongPressGestureRecognizer *longPress;

And in the viewDidLoad:

- (void)viewDidLoad
{      
    [longPress addTarget:self action:@selector(handleLongPress:)];
}

It's work perfectly, however when I use following code to recognize cell indexPath, it's wrong when one cell is expanded:

- (void)handleLongPress:(UILongPressGestureRecognizer*)sender {         
    // Get index path
    slidePickerPoint = [sender locationInView:self.tableView];
    NSIndexPath *indexPath= [self.tableView indexPathForRowAtPoint:slidePickerPoint]; 
    // It's wrong when 1 cell is expand and the cell's button I hold is below the expand button
}

Can anyone please show me how to get correct indexPath when there're different cell height?
Thank in advance

Upvotes: 2

Views: 3253

Answers (2)

Dinesh
Dinesh

Reputation: 6532

First add the long press gesture recognizer to the table view:

UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc] 
  initWithTarget:self action:@selector(handleLongPress:)];
lpgr.minimumPressDuration = 2.0; //seconds
lpgr.delegate = self;
[self.myTableView addGestureRecognizer:lpgr];
[lpgr release];

Then in the gesture handler:

-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
  if (gestureRecognizer.state == UIGestureRecognizerStateBegan)
  { 
    CGPoint p = [gestureRecognizer locationInView:self.myTableView];

    NSIndexPath *indexPath = [self.myTableView indexPathForRowAtPoint:p];
    if (indexPath == nil)
        NSLog(@"long press on table view but not on a row");
    else
        NSLog(@"long press on table view at row %d", indexPath.row);
    } 
}

You have to be careful with this so that it doesn't interfere with the user's normal tapping of the cell and also note that handleLongPress may fire multiple times before user lifts their finger.

Thanks...!

Upvotes: 0

Joel
Joel

Reputation: 16124

One way to do it would be to add a UILongPressGestureRecognizer to each UITableViewCell (that all use the same selector), then when the selector is called you can get the cell via sender.view. Perhaps not the most memory efficient, but if the single gesture recognizer won't return the right row in certain situations, this way should work.

Something like this:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    ...

    UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] 
  initWithTarget:self action:@selector(handleLongPress:)];
    [longPress setMinimumPressDuration:2.0];
    [cell addGestureRecognizer:longPress];
    [longPress release];

    return cell;
}

then

- (void)handleLongPress:(UILongPressGestureRecognizer*)sender {  
    UITableViewCell *selectedCell = sender.view;
}

Upvotes: 6

Related Questions