How can I keep track of the index path of a button in a table view cell?

半世苍凉 提交于 2019-11-28 04:43:53

I have created one Method for getting indexPath, Hope this will help you.

Create Button Action (aMethod:) in cellForRowAtIndexPath

-(void) aMethod:(UIButton *)sender
{
    // Calling Magic Method which will return us indexPath.
    NSIndexPath *indexPath = [self getButtonIndexPath:sender];

    NSLog(@"IndexPath: %li", indexPath.row);
    NSLog(@"IndexRow: %li", indexPath.section);
}

// Here is the Magic Method for getting button's indexPath

-(NSIndexPath *) getButtonIndexPath:(UIButton *) button
{
    CGRect buttonFrame = [button convertRect:button.bounds toView:groupTable];
    return [groupTable indexPathForRowAtPoint:buttonFrame.origin];
}

If you feel uncomfortable relying on button.superview, this method should be a little more robust than some of the other answers here:

UIButton *button = (UIButton *)sender;
CGRect buttonFrame = [button convertRect:button.bounds toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonFrame.origin];
Douwe Maan

This stopped working with iOS 7; check out Mike Weller's answer instead

- (IBAction)clickedButton:(id)sender {
    UIButton *button = (UIButton *)sender;
    UITableViewCell *cell = (UITableViewCell *)button.superview;
    UITableView *tableView = (UITableView *)cell.superview;
    NSIndexPath *indexPath = [tableView indexPathForCell:cell];
}

Or shorter:

- (IBAction)clickedButton:(id)sender {
    NSIndexPath *indexPath = [(UITableView *)sender.superview.superview indexPathForCell:(UITableViewCell *)sender.superview];
}

Both are untested!

Crawling up view hierarchies with .superview (like all of the existing answers demonstrate) is a really bad way to do things. If UITableViewCell's structure changes (which has happened before) your app will break. Seeing .superview.superview in your code should set off alarm bells.

The button and its handler should be added to a custom UITableViewCell subclass and layed out there. That's where it belongs.

The cell subclass can then delegate out the button event through a standard delegate interface, or a block. You should aim for something like this:

- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    MyCustomCell *cell = ...;

    // ...

    cell.onButtonTapped = ^{
        [self buttonSelectedAtIndexPath:indexPath];
    }

    // OR

    cell.delegate = self;

    // ...
}

(Note: if you go the block route, you will need to use a __weak self reference to prevent retain cycles, but I thought that would clutter up the example).

If you take the delegate route you would then have this delegate method to implement:

- (void)cellButtonPressed:(UITableViewCell *)cell
{
    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
    // ...
}

Your code now has full access to the appropriate context when it handles the event.

Implementing this interface on your cell class should be straightforward.

I don't know why I need to call the method superview twice to get the UITableViewCell.

Update:

Thank for Qiulang, now I got it.

"That's because SDK now has added a private class called UITableViewCellContentView for UITableViewCell, which is button's superview now." – Qiulang

UIButton *button = (UIButton *)sender;
UITableViewCell *cell = (UITableViewCell *)button.superview.superview;
UITableView *curTableView = (UITableView *)cell.superview;
NSIndexPath *indexPath = [curTableView indexPathForCell:cell];

I had this same issue also and built a simple recursive method that works no matter how many views deep you triggering control is.

-(NSIndexPath*)GetIndexPathFromSender:(id)sender{

    if(!sender) { return nil; }

    if([sender isKindOfClass:[UITableViewCell class]])
    {
        UITableViewCell *cell = sender;
        return [self.tableView indexPathForCell:cell];
    }

    return [self GetIndexPathFromSender:((UIView*)[sender superview])];
}


-(void)ButtonClicked:(id)sender{
    NSIndexPath *indexPath = [self GetIndexPathFromSender:sender];
}

Use this Perfect working for me.

CGPoint center= [sender center];
CGPoint rootViewPoint = [[sender superview] convertPoint:center toView:_tableView1];
NSIndexPath *indexPath = [_tableView1 indexPathForRowAtPoint:rootViewPoint];
NSLog(@"%@",indexPath);

SWIFT 2 UPDATE

Here's how to find out which button was tapped

 @IBAction func yourButton(sender: AnyObject) {


 var position: CGPoint = sender.convertPoint(CGPointZero, toView: self.tableView)
    let indexPath = self.tableView.indexPathForRowAtPoint(position)
    let cell: UITableViewCell = tableView.cellForRowAtIndexPath(indexPath!)! as
    UITableViewCell
    print(indexPath?.row)
    print("Tap tap tap tap")

}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!