带有 UIButton 的自定义 UITableViewCell:单击了哪个按钮?

Posted

技术标签:

【中文标题】带有 UIButton 的自定义 UITableViewCell:单击了哪个按钮?【英文标题】:Custom UITableViewCell with UIButton: which button has been clicked? 【发布时间】:2012-03-06 07:34:23 【问题描述】:

我正在使用最新的 SDK 和 XCode 4.2 开发一个 ios 4 应用程序。

我有一个 UITableView 带有部分和自定义 UITableViewCell。每个单元格都有一个 UIButton,所有这些按钮都具有相同的 UIControlEventTouchUpInside 目标。

这是我的代码:

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

    static NSString* cellIdentifier = @"CalendarCell";

    CalendarEventCell* cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

    if (cell == nil)
    
        NSArray* topLevelObjects =  [[NSBundle mainBundle] loadNibNamed:@"CalendarEventCell" owner:nil options:nil];

        for(id currentObject in topLevelObjects)
        
            if ([currentObject isKindOfClass:[CalendarEventCell class]])
            
                cell = (CalendarEventCell *)currentObject;
                [cell.addToCalendarButton addTarget:self action:@selector(addEventToiCal) forControlEvents:UIControlEventTouchUpInside];
                break;
            
        
    
...

当用户触摸该按钮内部时,我如何知道单击的单元格是在哪个部分和哪一行?

【问题讨论】:

您可以为该按钮设置标签。通过使用该标签号,您可以找出单击了哪个按钮。 看看这里:***.com/questions/510393/… 【参考方案1】:

在按钮上放置一个标签。例如:

CalendarEventCell* cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

if (cell == nil)

    NSArray* topLevelObjects =  [[NSBundle mainBundle] loadNibNamed:@"CalendarEventCell" owner:nil options:nil];

    for(id currentObject in topLevelObjects)
    
        if ([currentObject isKindOfClass:[CalendarEventCell class]])
        
            cell = (CalendarEventCell *)currentObject;
            [cell.addToCalendarButton addTarget:self action:@selector(addEventToiCal) forControlEvents:UIControlEventTouchUpInside];
            break;
        
    

cell.addToCalendarButton.tag = ((indexPath.section & 0xFFFF) << 16) |
                               (indexPath.row & 0xFFFF);

您需要将选择器更改为@selector(addEventToiCal:),并将方法更新为-(void) addEventToiCal:(UIButton *)sender

然后您可以将如下内容添加到-addEventToiCal:

if (!([sender isKindOfClass:[UIButton class]]))
    return;
NSUInteger section = ((sender.tag >> 16) & 0xFFFF);
NSUInteger row     = (sender.tag & 0xFFFF);
NSLog(@"Button in section %i on row %i was pressed.", section, row);

【讨论】:

您也可以将方法声明为- (void) addEventToiCal:(UIButton *)sender,然后删除第一行。 @MisterJack 我曾争论过这样写。由于您似乎支持该想法,因此我更新了答案以反映您的建议。 感谢您的回答。我需要 indexPath.section 和 indexPath.row。 标记方法很简单,但不能很好地扩展,特别是当向必须在控制器中识别的单元格添加更多控件并且您需要在行完成后更新标签时添加和删​​除。我已经看到它导致错误/问题太多次了。 @VansFannel 您可以使用类似tag = ((indexPath.section &amp; 0xFFFF) &lt;&lt; 16) | (indexPath.row &amp; 0xFFFF); 的方式对部分和行进行编码,然后使用类似以下方式对其进行解码:section = ((tag &gt;&gt; 16) &amp; 0xFFFF); row = (tag &amp; 0xFFFF);【参考方案2】:

将按钮的目标设置为单元格中的方法,而不是将目标设置为控制器本身,使用tappedButton:(UIButton *)button inCell:(UITableViewCell *)cell 之类的方法为单元格创建委托协议,并将控制器设置为单元格的委托。在目标方法中调用该委托方法。

然后在控制器的委托方法实现中,您可以通过调用UITableViewtableView:indexPathForCell:找到单元格的NSIndexPath

【讨论】:

将部分和行传递给tappedButton: 方法而不是调用tableView:indexPathForCell: 可能更容易,不是吗? 那么你必须将单元格的NSIndexPath 作为它的 ivar/property - 这也是可能的。但是你不必要地复制了你必须额外维护的数据——当细胞死亡时释放它,例如当细胞死亡时更新它。上面的单元格被添加或删除等等。但是,如果您在运行 tableView:indexPathForCell: 时遇到性能问题(这不太可能),您当然可以使用该“快捷方式”。【参考方案3】:

cellForRowAtIndexPath 方法中那样为按钮分配标签值

    cell.addToCalendarButton.tag=indexPath.row

    当您将方法添加到按钮时,也会发送发送者,因此将方法分配给按钮。

    [cell.addToCalendarButton addTarget:self action:@selector(addEventToiCal:)forControlEvents:UIControlEventTouchUpInside];

    在您的方法中,像这样读取相关行

    -(IBAction)addEventToiCal:(id)sender NSLog("当前行是 %d",[sender tag]);

如果你想现在关于该部分然后 indexPath 做这样的事情然后

- (void)addEventToiCal:(id)sender event:(id)event

    NSSet *touches = [event allTouches];
    UITouch *touch = [touches anyObject];
    CGPoint currentTouchPosition = [touch locationInView:self.tableView];
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint: currentTouchPosition];

   NsLog("value of indePath.section %d ,indexPath.row %d",indexPath.section,indexPath.row);


像这样在 cellforRowAtIndexPath 分配你的方法。

[cell.addToCalendarButton addTarget:self action:@selector(addEventToiCal:event:)forControlEvents:UIControlEventTouchUpInside];

【讨论】:

感谢您的回答。我需要 indexPath.section 和 indexPath.row。【参考方案4】:

BNRXIBCell 是一个出色的解决方案,适用于 iOS 5 及更高版本。它是一个 UITableViewCell 子类,旨在被子类化,以将操作消息从单元子视图转发到控制器。

【讨论】:

以上是关于带有 UIButton 的自定义 UITableViewCell:单击了哪个按钮?的主要内容,如果未能解决你的问题,请参考以下文章

带有 UIButton 的自定义 UITableViewCell:单击了哪个按钮?

带有圆形图像视图的自定义圆形 UIButton

以编程方式将 UIButton 添加到带有情节提要的自定义 ViewController

在具有动态高度的 IB uitableviewcell 中使用带有 XIB 的自定义视图

如何在目标c中创建带有标签和文本字段的自定义单元格

在主视图控制器的自定义单元格中使用来自 UIButton 的 IBAction