Ottieni clic con il pulsante all’interno di UITableViewCell

Ho un controller di visualizzazione con una vista tabella e un pennino separato per il modello di cella di tabella. Il modello di cella ha alcuni pulsanti. Voglio accedere al clic del pulsante insieme all’indice della cella cliccata all’interno del controller della vista dove ho definito la vista Tabella.

Quindi ho TableTemplate.m e TableTemplate.xib dove ho UITableView e TableTemplate.h , TableTemplate.m e TableTemplate.xib dove ho definito il pennino. Voglio l’evento click del pulsante con l’indice delle celle in ViewController.m .

Qualsiasi aiuto su come posso farlo?

1) Nel tuo cellForRowAtIndexPath: metodo, assegna tag pulsante come indice:

 cell.yourbutton.tag = indexPath.row; 

2) Aggiungi target e azione per il tuo pulsante come di seguito:

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

3) Azioni di codice basate su indice come sotto in ViewControler :

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

Aggiornamenti per più sezioni:

È ansible controllare questo collegamento per rilevare il clic del pulsante nella vista tabella per più righe e sezioni.

I delegati sono la strada da percorrere.

Come visto con altre risposte usando le viste potrebbe diventare obsoleto. Chi lo sa che domani potrebbe esserci un altro involucro e potrebbe essere necessario usare cell superview]superview]superview]superview] . E se si utilizzano i tag si finirebbe con n numero di condizioni if ​​else per identificare la cella. Per evitare tutti i delegati impostati. (In questo modo creerai una class di celle riutilizzabile. Puoi utilizzare la stessa class di celle di una class base e tutto ciò che devi fare è implementare i metodi delegati).

Per prima cosa abbiamo bisogno di un’interfaccia (protocollo) che verrà utilizzata dalla cella per comunicare i clic del pulsante (delegato). ( È ansible creare un file .h separato per il protocollo e includerlo nel controller della vista tabella e nelle classi di celle personalizzate OPPURE aggiungerlo in una class di celle personalizzata che verrà comunque inclusa nel controller di visualizzazione tabella )

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

Includi questo protocollo in un controller di visualizzazione di celle e tabelle personalizzato. E assicurarsi che il controller della vista tabella confermi questo protocollo.

Nella cella personalizzata crea due proprietà:

 @property (weak, nonatomic) iddelegate; @property (assign, nonatomic) NSInteger cellIndex; 

Nel clic del delegato UIButton IBAction: ( Lo stesso può essere fatto per qualsiasi azione nella class di cella personalizzata che deve essere delegata indietro per visualizzare il controller )

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

Nella vista tabella controller cellForRowAtIndexPath dopo aver desquamato la cella, impostare le proprietà sopra.

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

E implementare il delegato nel controller di visualizzazione tabella:

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

Questo sarebbe l’approccio ideale per ottenere azioni personalizzate dei pulsanti di cella nel controller di visualizzazione tabella.

Invece di giocare con i tag, ho adottato un approccio diverso. Reso delegato per la mia sottoclass di UITableViewCell (OptionButtonsCell) e aggiunto una variabile indexPath. Dal mio pulsante nello storyboard ho collegato @IBAction all’OptionButtonsCell e lì mando il metodo delegate con il giusto indexPath a chiunque sia interessato. Nella cella per il percorso dell’indice ho impostato indexPath corrente e funziona 🙂

Lascia che il codice parli da solo:

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)") } 

Questo dovrebbe aiutare:

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

Qui il mittente è l’istanza UIButton che sta inviando l’evento. myTableView è l’istanza di UITableView con cui hai a che fare.

Ottieni il riferimento alla cella e tutto il lavoro è fatto.

Potrebbe essere necessario rimuovere i pulsanti dal contenuto della cellaViewView e aggiungerli direttamente all’istanza di UITableViewCell come nella sottoview.

O

È ansible formulare uno schema di denominazione dei tag per diversi UIButtons in cell.contentView. Usando questo tag, in seguito puoi conoscere le informazioni su riga e sezione secondo necessità.

Il seguente codice potrebbe aiutarti.

Ho preso UITableView con una class di prototipo personalizzata chiamata UITableViewCell all’interno di UIViewController .

Quindi ho TableViewCell.h , TableViewCell.m e TableViewCell.h , TableViewCell.m

Ecco il codice per questo:

ViewController.h

 @interface ViewController : UIViewController @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; } 

Classe di celle personalizzate:

 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 

e

 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); } } 

Nota : qui ho preso tutti gli UIControls usando Storyboard.

Spero che possa aiutarti … !!!

Il motivo per cui mi piace la tecnica di seguito perché mi aiuta anche a identificare la sezione del tavolo.

Aggiungi pulsante nella cella 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]; 

Aggiungi evento:

 -(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; } } 

Spera questo aiuto

Swift 2.2

Devi aggiungere un objective per quel pulsante.

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

FunctionName: connesso // ad esempio

E ovviamente devi impostare il tag di quel pulsante da quando lo stai usando.

 myButton.tag = indexPath.row 

È ansible ottenere questo sottoclass UITableViewCell. Usalo nel generatore di interfaccia, rilascia un pulsante su quella cella, collegalo via presa e via.

Per ottenere il tag nella funzione connessa:

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

Il codice di Tarun non funziona su iOS7, poiché la struttura di UITableViewCell è cambiata e ora avrebbe ottenuto “UITableViewCellScrollView”.

Questo post Ottenere UITableViewCell con superview in iOS 7 ha una buona soluzione per creare un loop per trovare la corretta visualizzazione genitore, indipendentemente da eventuali futuri cambiamenti nella struttura. Si riduce alla creazione di un ciclo:

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

Il collegamento ha il codice per una soluzione più riutilizzabile, ma dovrebbe funzionare.

Trovo più semplice creare una sottoclass del pulsante all’interno della cella (Swift 3):

 class MyCellInfoButton: UIButton { var indexPath: IndexPath? } 

Nella tua class di cellule:

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

Nell’origine dati della vista tabella o della raccolta, quando si rimuove la cella, dare al pulsante il suo percorso dell’indice:

 cell.infoButton.indexPath = indexPath 

Quindi puoi semplicemente inserire questi codici nel tuo controller di visualizzazione tabella:

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

E non dimenticare di impostare la class del pulsante nel tuo Interface Builder e collegarlo alla funzione handleTapOnCellInfoButton !


modificato:

Utilizzando l’iniezione di dipendenza. Per impostare la chiusura di una chiamata:

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

e iniettare la chiusura nel metodo willDisplay del delegato della vista dell’insieme:

  func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { (cell as? MyCell)?.someFunction = { print(indexPath) // Do something with the indexPath. } } 

Swift 3 con una chiusura

Una buona soluzione consiste nell’usare una chiusura in un UITableViewCell personalizzato per richiamare il viewController per un’azione.

Nella cella:

 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() } } 

In View Controller: Delegato 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 } } 

Il suo lavoro per me.

  - (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 } 

La risposta @Mani è buona, tuttavia i tag di visualizzazione all’interno del contenuto della cella spesso vengono utilizzati per altri scopi. Puoi utilizzare il tag della cella (o il tag contentView della cella):

1) Nel tuo cellForRowAtIndexPath: metodo, assegna il tag della cella come indice:

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

2) Aggiungi target e azione per il tuo pulsante come di seguito:

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

3) Crea un metodo che restituisca una riga del mittente (grazie a @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) Azioni di codice basate su indice:

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

CustomTableCell.h è un UITableViewCell:

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

MyVC.m dopo le importazioni:

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

All’interno di “cellForRowAtIndexPath” in 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]; }