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

。_饼干妹妹 提交于 2019-11-27 00:37:28

问题


I have a table view where each cell has a button accessory view. The table is managed by a fetched results controller and is frequently reordered. I want to be able to press one of the buttons and obtain the index path of that button's table view cell. I've been trying to get this working for days by storing the row of the button in its tag, but when the table gets reordered, the row becomes incorrect and I keep failing at reordering the tags correctly. Any new ideas on how to keep track of the button's cell's index path?


回答1:


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



回答2:


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



回答3:


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!




回答4:


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.




回答5:


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



回答6:


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



回答7:


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



回答8:


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

}


来源:https://stackoverflow.com/questions/2863940/how-can-i-keep-track-of-the-index-path-of-a-button-in-a-table-view-cell

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