我有一个带有表视图的视图控制器和一个用于表格单元模板的单独的笔尖。单元格模板有一些按钮。我想访问按钮单击以及在我已定义表视图的视图控制器内单击的单元格的索引。
所以我有ViewController.h
和ViewController.m
我有UITableView
和TableTemplate.h
,TableTemplate.m
和TableTemplate.xib
我在哪里定义了笔尖。我希望单击索引的按钮单击事件在ViewController.m
。
有关如何做到这一点的任何帮助?
答案 0 :(得分:247)
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
}
}
多个部分的更新:
您可以检查this link以检测表格视图中的按钮点击多行和部分。
答案 1 :(得分:143)
代表是可行的方法。
正如其他使用视图的答案所见,可能会过时。谁知道明天可能会有另一个包装器,可能需要使用cell superview]superview]superview]superview]
。如果使用标签,最终会有n个if else条件来识别单元格。为了避免所有这些设置委托。 (通过这样做,您将创建一个可用的单元类。您可以使用相同的单元类作为基类,您所要做的就是实现委托方法。)
首先,我们需要一个接口(协议),单元格将使用它来进行通信(委托)按钮点击。 (您可以为协议创建一个单独的.h文件,并包含在表视图控制器和自定义单元类中,或者只将其添加到自定义单元类中,无论如何都会包含在表视图控制器中)
@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);
}
这是在表视图控制器中获取自定义单元格按钮操作的理想方法。
答案 2 :(得分:54)
我采用了不同的方法,而不是玩标签。为我的UITableViewCell子类(OptionButtonsCell)制作了委托,并添加了一个indexPath var。从我在故事板中的按钮,我将@IBAction连接到OptionButtonsCell,然后我向任何感兴趣的人发送带有正确indexPath的委托方法。在索引路径的单元格中,我设置了当前的indexPath,它可以工作:)
让代码说明一切:
Swift 3 Xcode 8
<强> OptionButtonsTableViewCell.swift 强>
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)")
}
答案 3 :(得分:29)
这应该有所帮助: -
UITableViewCell* cell = (UITableViewCell*)[sender superview];
NSIndexPath* indexPath = [myTableView indexPathForCell:cell];
此处发件人是发送事件的UIButton实例。 myTableView 是您正在处理的UITableView实例。
只需将单元格引用正确,所有工作都已完成。
您可能需要从单元格的contentView&amp;中删除按钮。 将它们直接添加到UITableViewCell实例,因为它是子视图。
或
您可以在cell.contentView中为不同的UIButton制定标签命名方案。 使用此标记,稍后您可以知道行和&amp;部分信息视需要。
答案 4 :(得分:21)
以下代码可能会帮助您。
我已在UITableView
内使用名为UITableViewCell
的自定义原型单元格类UIViewController
。
所以我有ViewController.h
,ViewController.m
和TableViewCell.h
,TableViewCell.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);
}
}
注意:我在这里使用了故事板获取了所有UIControls
。
希望能帮到你...... !!!
答案 5 :(得分:12)
我喜欢以下技术的原因,因为它也有助于我识别表格的部分。
在单元格cellForRowAtIndexPath中添加按钮:
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;
}
}
希望这有帮助。
答案 6 :(得分:6)
Tarun的代码无法在iOS7上运行,因为UITableViewCell结构已更改,现在他将获得&#34; UITableViewCellScrollView&#34;代替。
这篇文章Getting UITableViewCell with superview in iOS 7有一个很好的解决方案,可以创建一个循环来查找正确的父视图,而不管结构中是否有任何未来的变化。归结为创建一个循环:
UIView *superView = [sender superview];
UIView *foundSuperView = nil;
while (nil != superView && nil == foundSuperView) {
if ([superView isKindOfClass:[UITableViewCell class]]) {
foundSuperView = superView;
} else {
superView = superView.superview;
}
}
该链接包含更可重用的解决方案的代码,但这应该有效。
答案 7 :(得分:6)
您需要为该按钮添加目标。
myButton.addTarget(self, action: #selector(ClassName.FunctionName(_:), forControlEvents: .TouchUpInside)
功能名称:已连接 //例如
当然,您需要设置该按钮的标签,因为您正在使用它。
myButton.tag = indexPath.row
您可以通过继承UITableViewCell来实现这一目标。在界面构建器中使用它,在该单元格上放置一个按钮,通过插座连接它,然后就可以了。
要在连接的函数中获取标记:
func connected(sender: UIButton) {
let buttonTag = sender.tag
// Do any additional setup
}
答案 8 :(得分:5)
我觉得将单元格中的按钮(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!
}
不要忘记在界面生成器中设置按钮的类,并将其链接到handleTapOnCellInfoButton
函数!
编辑:
使用依赖注入。设置调用闭包:
class MyCell: UICollectionViewCell {
var someFunction: (() -> Void)?
...
@IBAction func didTapInfoButton() {
someFunction?()
}
}
并在集合视图的委托的willDisplay方法中注入闭包:
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
(cell as? MyCell)?.someFunction = {
print(indexPath) // Do something with the indexPath.
}
}
答案 9 :(得分:5)
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()
}
}
在View Controller中: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
}
}
答案 10 :(得分:4)
对我有用。
- (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];
}
答案 11 :(得分:4)
使用Swift闭包:
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
}
}
答案 12 :(得分:1)
// 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
}
答案 13 :(得分:1)
如果要使用闭包将参数值从单元格传递到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
}
}
答案 14 :(得分:0)
@Mani答案很好,但是单元格内容视图中的视图标记通常用于其他目的。您可以使用单元格的标记(或单元格的contentView标记):
1)在cellForRowAtIndexPath:
方法中,将单元格的标记指定为索引:
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
}
答案 15 :(得分:0)
CustomTableCell.h是一个UITableViewCell:
@property (weak, nonatomic) IBOutlet UIButton *action1Button;
@property (weak, nonatomic) IBOutlet UIButton *action2Button;
进口后的MyVC.m:
@interface MYTapGestureRecognizer : UITapGestureRecognizer
@property (nonatomic) NSInteger dataint;
@end
Inside&#34; cellForRowAtIndexPath&#34;在MyVC.m中:
//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];
MyVC.m:
-(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];
}
答案 16 :(得分:0)
快速4:
inside the cellForItemAt ,
cell.chekbx.addTarget(self, action: #selector(methodname), for: .touchUpInside)
then outside of cellForItemAt
@objc func methodname()
{
//your function code
}
答案 17 :(得分:-1)
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];
}