单击 UITableViewCell 中的按钮

我有一个带有表格视图的视图控制器和一个用于表格单元格模板的单独的笔尖。单元格模板有一些按钮。我想访问按钮点击以及在视图控制器中定义了 Table 视图的单元格的索引。

所以我有 ViewController.hViewController.m,其中我有 UITableViewTableTemplate.hTableTemplate.mTableTemplate.xib,其中我有笔尖定义。我想按钮点击事件与单元格索引在 ViewController.m

有什么办法吗?

229621 次浏览

1)在 cellForRowAtIndexPath:方法中,将按钮标签分配为索引:

cell.yourbutton.tag = indexPath.row;

2)为你的按钮添加目标和动作如下:

[cell.yourbutton addTarget:self action:@selector(yourButtonClicked:) forControlEvents:UIControlEventTouchUpInside];

3)根据以下 ViewControler的指数编写行动代码:

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

多部分的最新情况:

您可以选中 这个链接来检测表格视图中多行和多节的按钮单击。

这应该有所帮助:-

UITableViewCell* cell = (UITableViewCell*)[sender superview];
NSIndexPath* indexPath = [myTableView indexPathForCell:cell];

这里的 发件人是发送事件的 UIButton 实例。 MyTableView 是您正在处理的 UITableView 实例。

只要获得正确的单元格引用,所有工作就完成了。

您可能需要从单元格的 contentView & 中删除按钮 将它们作为子视图直接添加到 UITableViewCell 实例。

或者

可以在 cell.contentView 中为不同的 UIButtons 制定标记命名方案。 使用这个标记,以后您可以根据需要了解行和节信息。

Tarun 的代码在 iOS7上无法工作,因为 UITableViewCell 结构发生了变化,现在他得到的是“ UITableViewCellScrollView”。

这篇文章 在 iOS7中使用 superview 获得 UITableViewCell提供了一个很好的解决方案,创建一个循环来找到正确的父视图,不管结构未来有什么变化。它可以归结为创建一个循环:

    UIView *superView = [sender superview];
UIView *foundSuperView = nil;


while (nil != superView && nil == foundSuperView) {
if ([superView isKindOfClass:[UITableViewCell class]]) {
foundSuperView = superView;
} else {
superView = superView.superview;
}
}

这个链接有更可重用的解决方案的代码,但是这个应该可以工作。

代表团才是正确的选择。

从其他答案中可以看出,使用视图可能会过时。谁知道明天可能会有另一个包装器,可能需要使用 cell superview]superview]superview]superview]。如果你使用标签,你会得到 n 个 if else 条件来识别单元格。为了避免所有这些设置委托。(通过这样做,您将创建一个可重用的单元格类。您可以使用与基类相同的单元格类,只需实现委托方法即可。)

首先,我们需要一个接口(协议) ,它将被单元用来通信(委托)按钮点击

@protocol CellDelegate <NSObject>
- (void)didClickOnCellAtIndex:(NSInteger)cellIndex withData:(id)data;
@end

将此协议包含在自定义单元格和表视图控制器中。并确保表视图控制器确认此协议。

在自定义单元格中创建两个属性:

@property (weak, nonatomic) id<CellDelegate>delegate;
@property (assign, nonatomic) NSInteger cellIndex;

UIButton中 IBAction 委托单击: (对于自定义单元格类中需要委托回视图控制器的任何操作,也可以这样做)

- (IBAction)buttonClicked:(UIButton *)sender {
if (self.delegate && [self.delegate respondsToSelector:@selector(didClickOnCellAtIndex:withData:)]) {
[self.delegate didClickOnCellAtIndex:_cellIndex withData:@"any other cell data/property"];
}
}

在表视图控制器 cellForRowAtIndexPath中,调出单元格后,设置上述属性。

cell.delegate = self;
cell.cellIndex = indexPath.row; // Set indexpath if its a grouped table.

并在表视图控制器中实现委托:

- (void)didClickOnCellAtIndex:(NSInteger)cellIndex withData:(id)data
{
// Do additional actions as required.
NSLog(@"Cell at Index: %d clicked.\n Data received : %@", cellIndex, data);
}

这是在表视图控制器中获取自定义单元格按钮操作的理想方法。

我之所以喜欢下面的技术,是因为它也能帮助我识别表格的部分。

在 cell 中添加按钮 ForRowAtIndexPath:

 UIButton *selectTaskBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[selectTaskBtn setFrame:CGRectMake(15, 5, 30, 30.0)];
[selectTaskBtn setTag:indexPath.section]; //Not required but may find useful if you need only section or row (indexpath.row) as suggested by MR.Tarun
[selectTaskBtn addTarget:self action:@selector(addTask:)   forControlEvents:UIControlEventTouchDown];
[cell addsubview: selectTaskBtn];

事件 addTask:

-(void)addTask:(UIButton*)btn
{
CGPoint buttonPosition = [btn convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition];
if (indexPath != nil)
{
int currentIndex = indexPath.row;
int tableSection = indexPath.section;
}
}

希望这个能帮上忙。

以下代码可能对您有帮助。

我已经采取了 UITableView与自定义原型单元类名为 UITableViewCell内的 UIViewController

我有 ViewController.hViewController.mTableViewCell.hTableViewCell.m

下面是代码:

ViewController.h

@interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>


@property (strong, nonatomic) IBOutlet UITableView *tblView;


@end

ViewController.m

@interface ViewController ()


@end


@implementation ViewController


- (void)viewDidLoad {
[super viewDidLoad];


}


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


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


static NSString *cellIdentifier = @"cell";


__weak TableViewCell *cell = (TableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];


if (indexPath.row==0) {
[cell setDidTapButtonBlock:^(id sender)
{
// Your code here


}];
}
return cell;
}

自定义单元格类:

TableViewCell.h


@interface TableViewCell : UITableViewCell


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


@property (strong, nonatomic) IBOutlet UILabel *lblTitle;
@property (strong, nonatomic) IBOutlet UIButton *btnAction;


- (void)setDidTapButtonBlock:(void (^)(id sender))didTapButtonBlock;


@end

还有

UITableViewCell.m


@implementation TableViewCell


- (void)awakeFromNib {
// Initialization code
[self.btnAction addTarget:self action:@selector(didTapButton:) forControlEvents:UIControlEventTouchUpInside];


}


- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];


// Configure the view for the selected state
}
- (void)didTapButton:(id)sender {
if (self.didTapButtonBlock)
{
self.didTapButtonBlock(sender);
}
}

注意 : 这里我已经使用 Storyboard 拍摄了所有的 UIControls

希望能对你有所帮助... ! ! !

@ Mani 的回答很好,但是 cell 的 contentView 中的视图标签经常被用于其他目的。可以改用 cell 的标记(或 cell 的 contentView 标记) :

1)在 cellForRowAtIndexPath:方法中,将 cell 的标签指定为索引:

cell.tag = indexPath.row; // or cell.contentView.tag...

2)为你的按钮添加目标和动作如下:

[cell.yourbutton addTarget:self action:@selector(yourButtonClicked:) forControlEvents:UIControlEventTouchUpInside];

3)创建返回发件人行的方法(感谢@Stenio Ferreira) :

- (NSInteger)rowOfSender:(id)sender
{
UIView *superView = sender.superview;
while (superView) {
if ([superView isKindOfClass:[UITableViewCell class]])
break;
else
superView = superView.superview;
}


return superView.tag;
}

4)基于索引的代码行为:

-(void)yourButtonClicked:(UIButton*)sender
{
NSInteger index = [self rowOfSender:sender];
// Your code here
}

Swift 2.2

您需要为该按钮添加目标。

myButton.addTarget(self, action: #selector(ClassName.FunctionName(_:), forControlEvents: .TouchUpInside)

FunctionName: connect //例如

当然,您需要设置该按钮的标签,因为您正在使用它。

myButton.tag = indexPath.row

可以通过子类化 UITableViewCell 来实现这一点。用在 Interface Builder 上,在电池上按一个按钮,通过插座连接,就可以了。

要获取连接函数中的标记:

func connected(sender: UIButton) {
let buttonTag = sender.tag
// Do any additional setup
}

我没有使用标记,而是采用了不同的方法。为我的 UITableViewCell (OptionButtonsCell)子类创建委托,并添加了一个 indexPath 变量。从故事板中的按钮,我将@IBAction 连接到 OptionButtonsCell,在那里,我用正确的 indexPath 将委托方法发送给任何感兴趣的人。在单元格的索引路径,我设置当前的索引路径,它的工作:)

让代码自己说话吧:

Swift 3 Xcode 8

选项按钮

import UIKit
protocol OptionButtonsDelegate{
func closeFriendsTapped(at index:IndexPath)
}
class OptionButtonsTableViewCell: UITableViewCell {
var delegate:OptionButtonsDelegate!
@IBOutlet weak var closeFriendsBtn: UIButton!
var indexPath:IndexPath!
@IBAction func closeFriendsAction(_ sender: UIButton) {
self.delegate?.closeFriendsTapped(at: indexPath)
}
}

MyTableViewController. Swift

class MyTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, OptionButtonsDelegate {...


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "optionCell") as! OptionButtonsTableViewCell
cell.delegate = self
cell.indexPath = indexPath
return cell
}


func closeFriendsTapped(at index: IndexPath) {
print("button tapped at index:\(index)")
}

我发现最简单的子类化你单元格中的按钮(Swift 3) :

class MyCellInfoButton: UIButton {
var indexPath: IndexPath?
}

在你的牢房里:

class MyCell: UICollectionViewCell {
@IBOutlet weak var infoButton: MyCellInfoButton!
...
}

在表视图或集合视图的数据源中,在排队单元格时,给按钮指定其索引路径:

cell.infoButton.indexPath = indexPath

因此,您可以将这些代码放入表视图控制器:

@IBAction func handleTapOnCellInfoButton(_ sender: MyCellInfoButton) {
print(sender.indexPath!) // Do whatever you want with the index path!
}

不要忘记在你的 Interface Builder 中设置按钮的类,并将它链接到 handleTapOnCellInfoButton函数!


编辑:

使用依赖注入设置调用闭包:

class MyCell: UICollectionViewCell {
var someFunction: (() -> Void)?
...
@IBAction func didTapInfoButton() {
someFunction?()
}
}

并在集合视图的委托的 will Display 方法中注入闭包:

 func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
(cell as? MyCell)?.someFunction = {
print(indexPath) // Do something with the indexPath.
}
}
cell.show.tag=indexPath.row;
[cell.show addTarget:self action:@selector(showdata:) forControlEvents:UIControlEventTouchUpInside];


-(IBAction)showdata:(id)sender
{
UIButton *button = (UIButton *)sender;


UIStoryboard *storyBoard;
storyBoard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
SecondViewController *detailView = [storyBoard instantiateViewControllerWithIdentifier:@"SecondViewController"];


detailView.string=[NSString stringWithFormat:@"%@",[_array objectAtIndex:button.tag]];


[self presentViewController:detailView animated:YES completion:nil];


}

带闭包的 Swift 3

一个很好的解决方案是使用自定义 UITableViewCell 中的闭包回调 viewController 以执行某个操作。

单元格:

final class YourCustomCell: UITableViewCell {


var callbackClosure: (() -> Void)?


// Configure the cell here
func configure(object: Object, callbackClosure: (() -> Void)?) {
self.callbackClosure = callbackClosure
}




// MARK: - IBAction
extension YourCustomCell {
@IBAction fileprivate func actionPressed(_ sender: Any) {
guard let closure = callbackClosure else { return }
closure()
}
}

视图控制器: Tableview 委托

extension YourViewController: UITableViewDelegate {


func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
guard let cell: YourCustomCell = cell as? YourCustomCell else { return }
cell.configure(object: object, callbackClosure: { [weak self] in
self?.buttonAction()
})
}
}


fileprivate extension YourViewController {


func buttonAction() {
// do your actions here
}
}

H 是一个 UITableViewCell:

@property (weak, nonatomic) IBOutlet UIButton *action1Button;
@property (weak, nonatomic) IBOutlet UIButton *action2Button;

进口后的 MyVC.m:

@interface MYTapGestureRecognizer : UITapGestureRecognizer
@property (nonatomic) NSInteger dataint;
@end

在 MyVC.m 的“ cellForRowAtIndexPath”中:

//CustomTableCell
CustomTableCell *cell = (CustomTableCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];


//Set title buttons
[cell.action1Button setTitle:[NSString stringWithString:NSLocalizedString(@"action1", nil)] forState:UIControlStateNormal];
[cell.action2Button setTitle:[NSString stringWithString:NSLocalizedString(@"action2", nil)] forState:UIControlStateNormal];


//Set visibility buttons
[cell.action1Button setHidden:FALSE];
[cell.action2Button setHidden:FALSE];


//Do 1 action
[cell.action1Button addTarget:self action:@selector(do1Action :) forControlEvents:UIControlEventTouchUpInside];


//Do 2 action
MYTapGestureRecognizer *action2Tap = [[MYTapGestureRecognizer alloc] initWithTarget:self action:@selector(do2Action :)];
cancelTap.numberOfTapsRequired = 1;
cancelTap.dataint = indexPath.row;
[cell.action2Button setUserInteractionEnabled:YES];
[cell.action2Button addGestureRecognizer:action2Tap];

我的视频:

-(void)do1Action :(id)sender{
//do some action that is not necessary fr data
}


-(void)do2Action :(UITapGestureRecognizer *)tapRecognizer{
MYTapGestureRecognizer *tap = (MYTapGestureRecognizer *)tapRecognizer;
numberTag = tap.dataint;
FriendRequest *fr = [_list objectAtIndex:numberTag];


//connect with a WS o do some action with fr data


//actualize list in tableView
[self.myTableView reloadData];
}
// Add action in cell for row at index path -tableView


cell.buttonName.addTarget(self, action: #selector(ViewController.btnAction(_:)), for: .touchUpInside)


// Button Action


@objc func btnAction(_ sender: AnyObject) {






var position: CGPoint = sender.convert(.zero, to: self.tableView)




let indexPath = self.tableView.indexPathForRow(at: position)
let cell: UITableViewCell = tableView.cellForRow(at: indexPath!)! as
UITableViewCell








}

这对我有用。

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UIButton *Btn_Play = (UIButton *)[cell viewWithTag:101];
[Btn_Play addTarget:self action:@selector(ButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
}
-(void)ButtonClicked:(UIButton*)sender {
CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.Tbl_Name];
NSIndexPath *indexPath = [self.Tbl_Name indexPathForRowAtPoint:buttonPosition];
}

使用快速闭包:

class TheCell: UITableViewCell {


var tapCallback: (() -> Void)?


@IBAction func didTap(_ sender: Any) {
tapCallback?()
}
}


extension TheController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: TheCell.identifier, for: indexPath) as! TheCell {
cell.tapCallback = {
//do stuff
}
return cell
}
}

快速4:

inside the cellForItemAt ,
   

cell.chekbx.addTarget(self, action: #selector(methodname), for: .touchUpInside)


then outside of cellForItemAt
@objc func methodname()
{
//your function code
}

如果要使用闭包将参数值从单元格传递给 UIViewController,则

//Your Cell Class
class TheCell: UITableViewCell {


var callBackBlockWithParam: ((String) -> ()) = {_ in }


//Your Action on button
@IBAction func didTap(_ sender: Any) {
callBackBlockWithParam("Your Required Parameter like you can send button as sender or anything just change parameter type. Here I am passing string")
}
}


//Your Controller
extension TheController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: TheCell.identifier, for: indexPath) as! TheCell {
cell.callBackBlockWithParam = { (passedParamter) in


//you will get string value from cell class
print(passedParamter)
}
return cell
}
}