目标c - 处理自定义UITableViewCell按钮的按钮触摸事件的最佳实践

时间:2012-05-29 09:46:37

标签: objective-c ios uitableview uibutton

处理自定义UITableViewCell按钮的按钮触摸事件的最佳做法是什么?

我的课程: MyViewControllerMyCustomCell

我可以想到三个选择:

第一个选项 - 将该按钮作为MyCustomCell的属性,然后在MyViewController .m文件中添加一个目标,其中MyViewController为目标。

MyViewController .m文件

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"customCell";

    MyCustomCell *cell = (MyCustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
    cell = [[[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

    [cell.theButton addTarget:self
                       action:@selector(theButtonTapped:)
             forControlEvents:UIControlEventTouchUpInside];
    }

    // Configure the cell...    
    [self configureCell:cell atIndexPath:indexPath];

    return cell;
}

- (void)theButtonTapped:(UIButton *)sender
{
    MyCustomCell *selectedCell = (MyCustomCell *)sender.superview;

    if (selectedCell) {
        NSIndexPath *indexPath = [self.tableView indexPathForCell:selectedCell];
        MyModel *selectedModel = [self.model objectAtIndex:indexPath.row]; 

        // do something with the model...
    }
}

第二个选项 - 如果自定义单元格是在IB中创建的,请将nib文件的所有者设置为MyViewController,在buttonTapped:中实现MyViewController方法并连接按钮的Touch Up Inside事件为buttonTapped:方法。

第三个选项 - 如果未在IB中制作自定义单元格,请将目标添加到MyCustomCell .m文件中以MyCustomCell为目标的按钮。
定义MyCustomCellDelegate添加@property (nonatomic, assign) id<MyCustomCellDelegate> delegateMyCustomCell,并在按下按钮时调用此代理。
在创建单元格时设置MyViewController作为单元格的委托,并实现MyCustomCellDelegate协议。

MyCustomCell .h文件

@class MyCustomCell;  

@protocol MyCustomCellDelegate <NSObject>
- (void)buttonTappedOnCell:(MyCustomCell *)cell;
@end

@interface MyCustomCell : UITableViewCell

@property (nonatomic, retain) UIButton *theButton;
@property (nonatomic, assign) id<MyCustomCellDelegate> delegate;

@end

MyCustomCell .m文件

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // Initialization code
        self.theButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
        self.theButton.frame = CGRectMake(10,10,50,30);
        [self addSubview:self.theButton];

        [self.theButton addTarget:self
                           action:@selector(theButtonTapped:)
                 forControlEvents:UIControlEventTouchUpInside];
    }
    return self;
}

- (void)theButtonTapped:(UIButton *)sender
{
    [self.delegate buttonTappedOnCell:self];
}

MyViewController .m文件

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"customCell";

    MyCustomCell *cell = (MyCustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

        cell.delegate = self;
    }

    // Configure the cell...    
    [self configureCell:cell atIndexPath:indexPath];

    return cell;
}

- (void)buttonTappedOnCell:(MyCustomCell *)selectedCell
{
    if (selectedCell) {
        NSIndexPath *indexPath = [self.tableView indexPathForCell:selectedCell];
        MyModel *selectedModel = [self.model objectAtIndex:indexPath.row];

        // do something with the model...
    }
}

5 个答案:

答案 0 :(得分:11)

将单元格的行存储为自定义按钮的tag属性。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // bla bla bla
    if (!cell)
    {
        //bla bla bla
        [cell.yourButton addTarget:self selector:@selector(yourButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
    }
    // bla bla bla
    cell.yourButton.tag = indexPath.row;
}

-(void)yourButtonTapped:(id)sender
{
    int tag = [(UIButton *)sender tag];
    NSLog(@"tapped button in cell at row %i", tag);
}

答案 1 :(得分:1)

从我的角度来看,使用标记会破坏代码的严格性。此外,当你有多个部分时,使用标签肯定会使你的代码混乱。

要避免此问题,您可以继承UITableViewCell并使其保留indexPath属性,让单元格知道其精确位置。

此处的另一个问题是,如果UITableView调用API到insertdelete行,则必须更新可见的单元格&#39;位置数据

我认为这不是最好的做法。

有更好的方法。

我强烈建议您在单元格中处理不同的触摸事件时使用MVVM。

在此模式中,您的自定义UITableViewCell会包含自定义CellViewModel。此类将负责保存与单元格关联的所有数据,因此您可以检索数据并将事件处理逻辑放在单元格中。

答案 2 :(得分:0)

我通过子类化UIButton实现了基于块的方法:

typedef void (^ActionBlock)(id sender);

@interface UIBlockButton : UIButton {
     ActionBlock _actionBlock;
 } 

-(void)handleControlEvent:(UIControlEvents)event withBlock:(ActionBlock) action;
​@end

@implementation UIBlockButton

 -(void) handleControlEvent:(UIControlEvents)event withBlock:(ActionBlock) action
    {
      _actionBlock = action;
      [self addTarget:self action:@selector(callActionBlock:) forControlEvents:event];
      }

  -(void) callActionBlock:(id)sender{
     _actionBlock(sender);
   }

@end

在tableview委托中:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (!cell)
    {
     cell.yourButton.tag = indexPath.row;// pass tag
     [cell.yourButton handleControlEvent:UIControlEventTouchUpInside withBlock:^(id sender) {
     // your selector action code
     NSLog(@"tapped button in cell at row %i",[(UIButton *)sender tag]);
     }];
   }  
}

答案 3 :(得分:0)

在某些时候点击你的按钮,此时它是一个单元格的子视图,它是某个tableview的子视图。

只需编写一个获取视图的方法,在superview链上查找包含的单元格,进一步查找tableview,然后向tableview询问单元格的indexPath。

这比存储包含行的标记更容易,更可靠,因为在编辑tableview时不会遇到问题,并且让代码在需要时找出哪个indexPath要好得多indexPath,而不是在创建单元格时的某些完全不相关的代码。

答案 4 :(得分:0)

Swift 3.0解决方案

cell.btnRequest.tag = indexPath.row

cell.btnRequest.addTarget(self,action:#selector(buttonClicked(sender:)), for: .touchUpInside)

func buttonClicked(sender:UIButton) {

    let buttonRow = sender.tag
 }