如何在不使用sender.tag方法的情况下管理UItableViewCell中的UI按钮?

时间:2017-11-15 17:48:12

标签: ios objective-c uitableview uibutton

我有一个内有按钮的单元格。在我的cellForRowAtIndexPath方法中,我以这种方式回到我的uibutton:

UIButton *Button= (UIButton *) [cell viewWithTag:3];

我找到了一个解决方案,如下所示:

Button.tag = indexPath.row;

[Button addTarget:self action:@selector(yourButtonClicked:) forControlEvents:UIControlEventTouchUpInside];

-(void)yourButtonClicked:(UIButton*)sender
{
     if (sender.tag == 0) 
     {
         // Your code here
     }
}

但我的button.tag已用于从单元格内的其他视图中识别UI按钮视图,我无法将其用于indexpath.row。我的情况怎么办?

修改

最后我为UIButton制作了一个类别,它似乎是更快的可重用广告解决方案,但这里的每个答案都是有效的选项

3 个答案:

答案 0 :(得分:1)

您无需使用标记访问该按钮,然后为每个单元格设置Selector。我相信你可以实现更清洁的方法

第1步:

在“自定义”单元格中,将IBAction从单元格中的按钮拖到自定义单元格中。

@IBAction func buttonTapped(_ sender: Any) {
   //wait for implementation
} 

第2步:

在您的自定义单元格中,现在声明一个协议

protocol CellsProtocol : NSObjectProtocol {
    func buttonTapped(at index : IndexPath)
}

并且在同一个班级时,也要创建一些变量。

weak var delegate : CellsProtocol? = nil
var indexPath : IndexPath! = nil

我们很快就会看到这些变量的用法:)

第3步:

让我们回到刚刚拖动的IBAction

@IBAction func buttonTapped(_ sender: Any) {
     self.delegate?.buttonTapped(at: self.indexPath)
}

第4步:

现在您可以回到UITableViewController并确认刚刚宣布的协议

extension ViewController : CellsProtocol {
    func buttonTapped(at index: IndexPath) {
        //here you have indexpath of cell whose button tapped
    }
}

第5步:

现在最终将您的cellForRowAtIndexPath更新为

extension ViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell : MyTableViewCell = ;
        cell.indexPath = indexPath
        cell.delegate = self
    }
}

多数民众赞成:)现在你有一个按钮动作告诉你,按钮在哪个单元格中点击:)希望它有所帮助:)这是更通用的方法,因为即使你有多个uicomponents你仍然可以使用这种方法。

编辑1:

在下面的评论rmaddy中指出将indexPath作为属性单元格可能会导致问题,并且单元格不应该知道它的indexPath和协议应该被修改以返回单元格而不是返回索引路径。

引用评论:

  

不一定。您假设正在调用reloadData。您可以   有一个可见的单元格,然后在它上面插入一行。那个可见的细胞   没有更新,它的indexPath与单元格没有区别   您拥有的indexPath属性未更新。使用单元格本身   作为论点。它比传递索引路径好得多。如果   委托需要索引路径,委托可以询问表   查看单元格的当前索引路径。细胞永远不应该关心   或者知道它的索引路径是什么。

上面的陈述特别有道理,A小区永远不应该关心或知道它的索引路径是什么。因此,请在下面更新我的答案

第1步:

继续并删除单元格中的indexPath属性:

第2步:

将协议修改为

protocol CellsProtocol : NSObjectProtocol {
    func buttonTapped(in cell : UITableViewCell)
}

第3步:

将您的IBAction修改为

@IBAction func buttonTapped(_ sender: Any) {
    self.delegate?.buttonTapped(in: self)
}

第4步:

最后将ViewController中的协议确认修改为

extension ViewController : CellsProtocol {

    func buttonTapped(in cell: UITableViewCell) {
        let indexPath = self.tableView.indexPath(for: cell)
        //here you have indexpath of cell whose button tapped
    }
}

多数民众赞成:)

答案 1 :(得分:1)

创建UIButton的自定义按钮子类,并根据需要定义属性。 Button.tag是默认标识符。在自定义类中,您可以根据需要提供尽可能多的属性。然后使用此自定义按钮类而不是UIButton。用户自定义属性后跟点(。),就像标记一样。

答案 2 :(得分:1)

另一种选择 - 使用“回拨”块。

这假设您有一个带有“btnCell”标识符的Prototype单元格,其中包含连接到下面显示的- (IBAction)buttonTapped:(id)sender方法的UIButton ...

你的细胞类:

//
//  WithButtonTableViewCell.h
//
//  Created by Don Mag on 11/15/17.
//

#import <UIKit/UIKit.h>

@interface WithButtonTableViewCell : UITableViewCell

- (void)setButtonTappedBlock:(void (^)(id sender))buttonTappedBlock;

@end

//
//  WithButtonTableViewCell.m
//
//  Created by Don Mag on 11/15/17.
//

#import "WithButtonTableViewCell.h"

@interface WithButtonTableViewCell ()

@property (copy, nonatomic) void (^buttonTappedBlock)(id sender);

@end

@implementation WithButtonTableViewCell

- (IBAction)buttonTapped:(id)sender {
    // call back if the block has been set
    if (self.buttonTappedBlock) {
        self.buttonTappedBlock(self);
    }
}

@end

您的表视图控制器类:

//
//  WithButtonTableViewController.h
//
//  Created by Don Mag on 7/12/17.
//

#import <UIKit/UIKit.h>

@interface WithButtonTableViewController : UITableViewController

@end

//
//  WithButtonTableViewController.m
//
//  Created by Don Mag on 11/15/17.
//

#import "WithButtonTableViewController.h"
#import "WithButtonTableViewCell.h"

@interface WithButtonTableViewController ()

@end

@implementation WithButtonTableViewController

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 20;
}

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

    WithButtonTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"btnCell" forIndexPath:indexPath];

    [cell setButtonTappedBlock:^(id sender) {

        NSLog(@"Button in cell at row %ld in section: %ld was tapped", (long)indexPath.row, (long)indexPath.section);

        // sender is the cell
        // do whatever else you want here...

    }];

    return cell;

}

@end

现在,当点击单元格中的按钮时,它将“回调”到视图控制器,此时块内的代码将被执行。