У меня есть контроллер представления с табличным представлением и отдельным наконечником для шаблона ячейки таблицы. В шаблоне ячейки есть несколько кнопок. Я хочу получить доступ к нажатию кнопки вместе с индексом ячейки, нажатой внутри контроллера представления, в котором я определил представление таблицы.
Итак, у меня есть ViewController.h
and, ViewController.m
где у меня есть UITableView
и TableTemplate.h
, TableTemplate.m
и TableTemplate.xib
где у меня определено перо. Я хочу, чтобы событие нажатия кнопки с индексом ячейки в ViewController.m
.
Любая помощь о том, как я могу это сделать?
источник
Делегаты - это то, что нужно.
Как видно из других ответов, использование представлений может устареть. Кто знает, завтра может появиться еще одна обертка и, возможно, потребуется ее использовать
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); }
Это был бы идеальный подход для получения настраиваемых действий кнопок ячейки в контроллере табличного представления.
источник
Вместо того, чтобы играть с тегами, я применил другой подход. Сделал делегатом для моего подкласса UITableViewCell (OptionButtonsCell) и добавил переменную indexPath. С помощью моей кнопки в раскадровке я подключил @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)") }
источник
class MyTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, OptionButtonsDelegate
Можете ли вы мне помочь, я получаю сообщение об ошибке в этой строке: // error: Избыточное соответствие MyTableViewController протоколу UITableViewDataSourceЭто должно помочь: -
UITableViewCell* cell = (UITableViewCell*)[sender superview]; NSIndexPath* indexPath = [myTableView indexPathForCell:cell];
Здесь отправитель - это экземпляр UIButton, который отправляет событие. myTableView - это экземпляр UITableView, с которым вы имеете дело.
Просто установите правильную ссылку на ячейку, и вся работа сделана.
Возможно, вам придется удалить кнопки из contentView ячейки и добавить их непосредственно в экземпляр UITableViewCell в качестве подпредставления.
Или
Вы можете сформулировать схему именования тегов для различных UIButton в cell.contentView. Используя этот тег, позже вы можете узнать информацию о строке и разделе, если это необходимо.
источник
Следующий код может вам помочь.
Я взял
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
использовал Storyboard.Надеюсь, что это поможет вам ... !!!
источник
Причина, по которой мне нравится техника ниже, потому что она также помогает мне идентифицировать раздел таблицы.
Добавить кнопку в ячейке 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; } }
Надеюсь на эту помощь.
источник
Используйте закрытия 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 } }
источник
Код Таруна не работает на iOS7, поскольку структура UITableViewCell изменилась, и теперь вместо этого он получит «UITableViewCellScrollView».
В этом посте Получение UITableViewCell с супервизором в 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; } }
По ссылке есть код для решения, которое можно использовать повторно, но это должно сработать.
источник
Swift 2.2
Вам нужно добавить цель для этой кнопки.
myButton.addTarget(self, action: #selector(ClassName.FunctionName(_:), forControlEvents: .TouchUpInside)
FunctionName: connected // например
И, конечно, вам нужно установить тег этой кнопки, поскольку вы ее используете.
Вы можете добиться этого, создав подкласс UITableViewCell. Используйте его в построителе интерфейса, поместите кнопку в эту ячейку, подключите ее к розетке и готово.
Чтобы получить тег в подключенной функции:
func connected(sender: UIButton) { let buttonTag = sender.tag // Do any additional setup }
источник
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() } }
Контроллер представления: делегат представления таблицы
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 } }
источник
Я считаю, что проще всего создать подкласс кнопки внутри вашей ячейки (Swift 3):
class MyCellInfoButton: UIButton { var indexPath: IndexPath? }
В вашем классе ячеек:
class MyCell: UICollectionViewCell { @IBOutlet weak var infoButton: MyCellInfoButton! ... }
В источнике данных табличного представления или представления коллекции при исключении ячейки из очереди укажите для кнопки путь индекса:
Итак, вы можете просто поместить этот код в контроллер табличного представления:
@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. } }
источник
Это работа для меня.
- (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]; }
источник
// 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 }
источник
для быстрого 4:
источник
Если вы хотите передать значение параметра из ячейки в 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 } }
источник
@Mani ответ хорош, однако теги представлений внутри contentView ячейки часто используются для других целей. Вместо этого вы можете использовать тег ячейки (или тег 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 }
источник
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
Внутри cellForRowAtIndexPath в 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]; }
источник
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]; }
источник