如何跟踪表视图单元格中按钮的索引路径?

22

我有一个表格视图,每个单元格都有一个按钮附件视图。该表由一个获取结果控制器管理,并经常重新排序。我想能够按下其中一个按钮并获得该按钮的表格视图单元格的索引路径。我一直在尝试存储按钮的行号,但当表格被重新排序时,行号会变得不正确,并且我一直无法正确地重新排序标记。有没有新的想法来跟踪按钮的单元格的索引路径?


8个回答

31

如果你不舒服依赖于button.superview,那么这个方法应该比其他答案更稳健:

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

25

这在iOS 7上不再适用; 可以查看Mike Weller的答案

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

更短的写法:

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

两者都未经测试!


非常感谢!这个解决方案有效了,现在我终于可以继续进行了 :)对于那些稍后来到这里并想要实施此方法的人,在第一个示例中,您需要少一个superview调用才能获取UITableViewCell,而且superview都是小写的。否则,一切都很完美(我没有尝试过更短的示例)。 - Jake
你是对的,我编辑了我的回答 ;) 我在使用2个 .superviews 来获取 UITableViewCell 的逻辑是:单元格是 accessoryViewsuperview,而 accessoryView 又是 UIButtonsuperview。不过我想我错了。 - Douwe Maan
这可能有效,但是沿着视图层次结构爬行至少是一种“坏味道”。如果UITableViewCell的视图结构发生更改,您的应用程序会瘫痪。而这在过去曾经发生过。按钮及其处理程序应存在于自定义单元格子类中。这个单元格类可以提供委托或块回调接口,以便您的视图控制器可以通过这种方式钩入按钮事件,并完全访问相应的上下文。 - Mike Weller
请查看我的答案以获取更多细节。 - Mike Weller
7
@MikeWeller 确认味道。这在iOS7中无法使用了。cell.superView现在返回UITableViewWrapperView而不是tableView本身。 - memmons
是的,在回顾中,我的答案很糟糕。我已经链接到Mike Weller的答案了。 - Douwe Maan

21

使用.superview来遍历视图层次结构(就像所有现有答案所展示的那样)是一种非常糟糕的做法。如果UITableViewCell的结构发生变化(这曾经发生过),您的应用程序将会崩溃。在您的代码中看到.superview.superview应该引起警觉。

按钮及其处理程序应添加到自定义的UITableViewCell子类中,并在那里进行布局。那是它所属的地方。

然后,该单元格子类可以通过标准委托界面或块委托出按钮事件。您应该朝着这样的目标努力:

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

    // ...

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

    // OR

    cell.delegate = self;

    // ...
}
(Note: 如果你选择使用 block,你需要使用 __weak self 引用来防止保留环路,但我认为这会让示例显得杂乱无序)。
如果你选择使用代理,你需要实现以下代理方法:
- (void)cellButtonPressed:(UITableViewCell *)cell
{
    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
    // ...
}

当处理事件时,您的代码现在可以完全访问适当的上下文。

在您的单元格类上实现此接口应该很简单。


9
我不知道为什么需要调用两次superview方法才能获得UITableViewCell。
更新:
感谢Qiulang的解答,现在我明白了。
“这是因为SDK现在添加了一个名为UITableViewCellContentView的私有类,它是UITableViewCell的按钮superview。” - Qiulang
UIButton *button = (UIButton *)sender;
UITableViewCell *cell = (UITableViewCell *)button.superview.superview;
UITableView *curTableView = (UITableView *)cell.superview;
NSIndexPath *indexPath = [curTableView indexPathForCell:cell];

3
这是因为SDK现在为UITableViewCell添加了一个名为UITableViewCellContentView的私有类,它是按钮的父视图。 - Qiulang

6

我也遇到了同样的问题,我构建了一个简单的递归方法,无论你触发控件有多深,它都可以正常工作。

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

小心无限递归...我可能会在该方法顶部添加一个逃生口来保险起见:if(!sender) { return nil; } - wxactly
这个 getIndexPathFromSender 方法真是太棒了! - Yup.

4

我创建了一个用于获取indexPath的方法,希望这对你有所帮助。

在cellForRowAtIndexPath中创建按钮操作(aMethod:)

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

// 这是获取按钮indexPath的神奇方法

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

3
使用这个对我来说完美运作。
CGPoint center= [sender center];
CGPoint rootViewPoint = [[sender superview] convertPoint:center toView:_tableView1];
NSIndexPath *indexPath = [_tableView1 indexPathForRowAtPoint:rootViewPoint];
NSLog(@"%@",indexPath);

2

SWIFT 2 更新

以下是如何查找点击的按钮的方法

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

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接