如果 UITableViewCell 有多个按钮,那么处理触摸事件的最佳位置在哪里

Posted

技术标签:

【中文标题】如果 UITableViewCell 有多个按钮,那么处理触摸事件的最佳位置在哪里【英文标题】:If a UITableViewCell has multiple buttons, where is the best place to handle touch events 【发布时间】:2014-05-09 13:11:33 【问题描述】:

我以具有多列的表格格式呈现大量数据。几乎每一列都有一个按钮(总共最多 4 个),每一行都是一个UITableViewCell

如何检测到按钮被触摸以及应该在哪里处理按钮的触摸事件?我敢肯定,它不应该是 didSelectRowAtIndexPath 方法。

一旦我可以检测到按下了哪个按钮,我就会获取该特定行中的数据并对其进行操作。所以,我需要知道该行的indexPath,以及上面按下了什么按钮。

【问题讨论】:

这 4 个按钮是否都有不同的操作? @JefferyThomas .. 是的 使用视图标签调用控件。 【参考方案1】:

您可以使用 rowcolumn 两个属性对 UIButton 进行子类化,并实现以下逻辑:

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

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"
                                                        forIndexPath:indexPath];

    MyButton *button1 = (MyButton *)[cell viewWithTag:1];
    button1.row = indexPath.row;
    button1.column = 1; // view tag
   [button1 addTarget:self
            action:@selector(clickAction:)
  forControlEvents:UIControlEventTouchUpInside];

    // button2,button3...

    return cell;


-(void)clickAction:(MyButton *)sender 
   // now you can known which button
   NSLog(@"%ld %ld", (long)sender.row, (long)sender.column); 

【讨论】:

【参考方案2】:

笼统的不详细回答:

    创建 UITableviewcell 子类,将单元格 ui 元素链接到此类。 添加方法configureWithModel:(Model*)model; //模型是您希望单元格表示的信息 操纵该信息或 如果您需要操作屏幕或其他对象。创建单元格时,您需要为表格视图单元格子类提供对其他对象的引用。 (在代码、故事板或 nib 中)。

如何在 ios 7 中处理按钮按下:Button in UITableViewCell not responding under ios 7(将表格单元格选择设置为无)

如何链接按钮:http://oleb.net/blog/2011/06/creating-outlets-and-actions-via-drag-and-drop-in-xcode-4/

【讨论】:

【参考方案3】:

如果这四个视图是UIButton,那么您将在每个按钮上收到点击事件,或者如果它们不是UIButton,那么您应该在每个视图上添加UITapGestureReconiser

【讨论】:

这些不是不同的视图.. 我打算将它实现为 UITableView 中可滚动的自定义 UITableViewCell .. 因此.. 通常.. 每行都是一个 UITableViewCell 只是不要实现 didSelectRowAtIndexPath 委托方法,并让按钮处理自己的触摸事件,但请记住,手势会覆盖触摸事件,因此如果您拖动 tableview 将滚动并且按钮不会轻拍 @A'saDickens ,嗯..我需要处理大数据的滚动...但是我应该在哪里添加动作,在 CustomCell 类或 tableview 中.. 就个人而言,我会设置一个委托,并且单元格会调用一个委托方法 [self.delegate touchOneButtonFromCell:self],只有当视图控制器需要处理回调时,如果单元格可以处理回调我会让单元处理它。无论操作将在您的单元格类中设置,因此您应该有 IBOutlet(s) 并将它们链接到您的故事板或 xib 文件中 通常你会将DataModel存储在单元格中......也就是在参数中,你会说cell.user并且你不需要存储索引路径【参考方案4】:

这里有几个选项。但我会做以下事情:

在您的自定义单元类中采用委托协议(参见此处:How to declare events and delegates in Objective-C?)。这将处理按钮的目标选择器。将此消息与发送者一起传递回您的视图控制器。要检测它所在的单元格,请执行以下操作:

CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tableView];
CGRect senderFrame = CGRectMake(buttonPosition.x, buttonPosition.y, sender.frame.size.width, sender.frame.size.height);

从这里你可以决定做什么。使用按钮 .x 坐标来确定它是哪个按钮,或者为 cellForRowAtIndexPath: 中的每个按钮指定不同的标记。或者,如果您想获取单元格的索引路径,您可以这样做:

NSArray *indexPaths = [YOUR_TABLE_VIEW indexPathsForRowsInRect:senderFrame];
NSIndexPath *currentIndexPath = [indexPaths lastObject];

【讨论】:

【参考方案5】:

因为每个按钮都有不同的动作,所以您在运行时唯一需要获取的是按钮的 indexPath。这可以通过查看按钮的超级视图直到找到一个单元格来完成。

- (IBAction)action1:(UIButton *)button

    UITableViewCell *cell = [self cellContainingView:button];
    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];

    MyDataModel *object = self.objects[indexPath.row];
    // perform action1 on the data model object

    // Now that the data model behind indexPath.row was done, reload the cell
    [self.tableView reloadRowsAtIndexPaths:@[indexPath]
                          withRowAnimation: UITableViewRowAnimationAutomatic];


- (id)cellContainingView:(UIView *)view

    if (view == nil)
        return nil;

    if ([view isKindOfClass:[UITableViewCell class]])
        return view;

    return [self cellContainingView:view.superview];

那里:没有委托,没有标签,并且操作不关心单元的内部。

您仍然希望使用四个按钮子类化UITableViewCell(如果您没有更好的名称,请称它们为 button1、button2、button3 和 button4)。你可以让所有的连接都是Interface Builder。这只需要在 -tableView:cellForRowAtIndexPath: 期间将对象数据填充到单元格中。

【讨论】:

【参考方案6】:

理想情况下,您应该通过子类化UITableViewCell 创建一个自定义单元格,并为该单元格中的每个按钮实现操作。如果您的视图控制器需要了解这些操作,您可以定义一个协议,MyCustomCellDelegate 或类似的,并让您的视图控制器符合该协议。然后MyCustomCell 将能够在用户与其按钮或其他控件交互时向视图控制器发送消息。

如以下示例代码所示,您可以在情节提要或 nib 中创建一个单元格,并将其中一个按钮的操作挂钩到 CustomTableCell 类的 firstButtonAction 方法。

另外,您需要将视图控制器设置为创建的 CustomTableCell 对象的委托属性,并在视图控制器类中实现 CustomTableCellDelegate 的 buttonActionAtIndex: 方法。使用传递给此方法的 controlIndexInCell 参数来确定可能是哪个按钮生成了操作。

   @protocol CustomTableCellDelegate <NSObject>

   - (void) buttonActionAtIndex:(NSInteger)controlIndexInCell

   @end

在 CustomTableCell.h 类中

   @interface CustomTableCell: UITableViewCell
   @property (nonatomic, weak) id <CustomTableCellDelegate> delegate

   - (IBAction) firstButtonAction:(id)sender

   @end

在 CustomTableCell.m 类中

   @implementation CustomTableCell
   @synthesize delegate

   - (IBAction) firstButtonAction:(id)sender
         if ([delegate respondToSelector:@selector(buttonActionAtIndex:)])
            [delegate buttonActionAtIndex:0];
    

   @end

【讨论】:

我在同一条轨道上..你能详细说明协议和委托部分吗..【参考方案7】:

这是我喜欢如何处理此类情况的个人偏好,但我首先将UITableViewCell 子类化,因为您的表格单元格看起来不像默认的 iOS UITableViewCell。基本上你有一个自定义设置,所以你需要一个自定义类。

从那里你应该在你的头文件中设置你的 4 个IBActions

- (IBAction)touchFirstButton;
- (IBAction)touchSecondButton;
- (IBAction)touchThirdButton;
- (IBAction)touchFourthButton;

您不需要在这些操作中传递发送者,因为您不会在这些方法中使用该对象。正在创建它们以转接呼叫。

之后为你的 UITableViewSubClass 设置一个协议

@protocol UITableViewSubClassDelegate;

记得把它放在@interface声明之前

给您的销售委托财产

@property (nonatomic, strong) id<UITableViewSubClassDelegate> delegate;

最后定义你的实际协议,你需要设置 4 个方法,每个按钮 1 个,并将你的子类作为参数

@protocol UITableViewSubClassDelegate <NSObject>

   - (void)forwardedFirstButtonWithCell:(UITableViewSubClass*)cell;
   - (void)forwardedSecondButtonWithCell:(UITableViewSubClass*)cell;
   - (void)forwardedThirdButtonWithCell:(UITableViewSubClass*)cell;
   - (void)forwardedFourthButtonWithCell:(UITableViewSubClass*)cell;

@end

这将被放置在底部的@interface @end 部分之外

然后在你的@interface 和@implementation 中创建一个configureWithModel: 方法以及你的模型的一个属性

@接口:

@property (nonatomic, strong) Model *model;
- (void)configureWithModal:(Model*)model;

@实现:

- (void)configureWithModal:(Model*)model 
   self.model = model;
   // custom UI set up

从这里您应该在@implementation 文件中配置您的操作方法以调用委托方法,我只显示第一个,但您可以使用所有 IBActions 来执行此操作

- (void)configureWithModal:(Model*)model 
   [self.delegate forwardFirstButtonWithCell:self];

从这里您的自定义单元格设置完成,我们需要返回显示 UITableView 的 UIViewController。首先进入视图控制器的头文件,导入你自定义的 UITableViewCellSubClass,然后设置类来实现这个协议。

它应该看起来像这样

@interface MYViewController : UIViewController <UITableViewSubClassDelegate>

从那里你应该进入你的 cellForRowAtIndexPath: 方法并配置你的自定义 UITableViewCell

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

   UITableViewCellSubClass *cell = [tableView dequeueReusableCellWithIdentifier:@"CellIdentifier"];
   cell.delegate = self;

   Model *cellModel = self.tableData[indexPath.row];
   [cell configureWithModel:cellModel];

   return cell;


现在进入您的单元类并将所有协议方法复制粘贴到您的 viewController 类中。我将展示一个作为示例。

在你的 UIViewController 中:

- (void)forwardedFirstButtonWithCell:(UITableViewSubClass*)cell 
   Model *cellModel = cell.model;
   // do stuff with model from outside of the cell

对所有方法都这样做,你应该会很好。

请记住将所有#imports 放入其中,这样就没有前向声明,并记住将 IBActions 链接到您的故事板或 xib 文件。如果您想为表格单元格自定义 xib,则必须检查单元格是否为 nil,然后分配一个新单元格,但如果您使用的是原型单元格,那么这就足够了。

为简单起见,我提出了FirstButtonWithCell: 但我鼓励将名称命名为描述其正在执行的操作,例如 displayPopOverToEnterData 或类似名称。从那里您甚至可以更改委托协议方法的参数以采用模型而不是

- (void) displayPopOverToEnterDataWithCell:(UITableViewSubClass*)cell;

做起来

- (void) displayPopOverToEnterDataWithModel:(Model*)model;

但是,我不知道您需要从单元格中访问什么类型的信息。因此,请根据需要更新这些方法。

【讨论】:

以上是关于如果 UITableViewCell 有多个按钮,那么处理触摸事件的最佳位置在哪里的主要内容,如果未能解决你的问题,请参考以下文章

在 UITableviewcell 中调用多个按钮

点击时无法更改 UItableViewCell 中按钮的图像

检测点击UITableViewCell中包含多个部分的UITableView的按钮

在 UITableviewCell 中显示下载进度

iOS UITableViewCell的"滑动出现多个按钮"

“自上而下” UITableView 中的 UITableViewCell 中的多个按钮