Détecter quel UIButton a été pressé dans une UITableView

J’ai un UITableView avec 5 UITableViewCells . Chaque cellule contient un UIButton configuré comme suit:

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSSsortingng *identifier = @"identifier"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; if (cell == nil) { cell = [[UITableView alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]; [cell autorelelase]; UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(10, 5, 40, 20)]; [button addTarget:self action:@selector(buttonPressedAction:) forControlEvents:UIControlEventTouchUpInside]; [button setTag:1]; [cell.contentView addSubview:button]; [button release]; } UIButton *button = (UIButton *)[cell viewWithTag:1]; [button setTitle:@"Edit" forState:UIControlStateNormal]; return cell; } 

Ma question est la suivante: dans la méthode buttonPressedAction: comment savoir quel bouton a été pressé? J’ai envisagé d’utiliser des tags mais je ne suis pas sûr que ce soit le meilleur itinéraire. J’aimerais pouvoir, d’une manière ou d’une autre, étiqueter l’ indexPath sur le contrôle.

 - (void)buttonPressedAction:(id)sender { UIButton *button = (UIButton *)sender; // how do I know which button sent this message? // processing button press for this row requires an indexPath. } 

Quelle est la manière standard de faire cela?

Modifier:

Je l’ai un peu résolu en faisant ce qui suit. J’aimerais quand même avoir un avis sur le fait de savoir s’il s’agit de la méthode standard ou s’il existe une meilleure solution.

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSSsortingng *identifier = @"identifier"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; if (cell == nil) { cell = [[UITableView alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]; [cell autorelelase]; UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(10, 5, 40, 20)]; [button addTarget:self action:@selector(buttonPressedAction:) forControlEvents:UIControlEventTouchUpInside]; [cell.contentView addSubview:button]; [button release]; } UIButton *button = (UIButton *)[cell.contentView.subviews objectAtIndex:0]; [button setTag:indexPath.row]; [button setTitle:@"Edit" forState:UIControlStateNormal]; return cell; } - (void)buttonPressedAction:(id)sender { UIButton *button = (UIButton *)sender; int row = button.tag; } 

Ce qui est important de noter, c’est que je ne peux pas définir la balise dans la création de la cellule car la cellule peut être retirée de la queue à la place. C’est très sale. Il doit y avoir un meilleur moyen.

Dans l’exemple d’ accessoire d’Apple, la méthode suivante est utilisée:

 [button addTarget:self action:@selector(checkButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; 

Ensuite, dans le gestionnaire tactile, les coordonnées tactiles récupérées et le chemin d’indexation sont calculés à partir de cette coordonnée:

 - (void)checkButtonTapped:(id)sender { CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tableView]; NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition]; if (indexPath != nil) { ... } } 

J’ai trouvé que la méthode d’utilisation de la superview de la superview pour obtenir une référence à l’indexPath de la cellule fonctionnait parfaitement. Merci à iphonedevbook.com (macnsmith) pour le texte du lien

 -(void)buttonPressed:(id)sender { UITableViewCell *clickedCell = (UITableViewCell *)[[sender superview] superview]; NSIndexPath *clickedButtonPath = [self.tableView indexPathForCell:clickedCell]; ... } 

Voici comment je le fais. Simple et concis:

 - (IBAction)buttonTappedAction:(id)sender { CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tableView]; NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition]; ... 

J’ai trouvé une bonne solution à ce problème ailleurs, sans déconner les tags sur le bouton:

 - (void)buttonPressedAction:(id)sender { NSSet *touches = [event allTouches]; UITouch *touch = [touches anyObject]; CGPoint currentTouchPosition = [touch locationInView:self.tableView]; NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint: currentTouchPosition]; do stuff with the indexPath... } 

Que diriez-vous d’envoyer des informations comme NSIndexPath dans UIButton utilisant l’injection d’exécution.

1) Vous avez besoin de l’exécution à l’importation

2) append une constante statique

3) append NSIndexPath à votre bouton lors de l’exécution en utilisant:

(void) setMetaData: (id) target avecObject: (id) newObj

4) sur le bouton, obtenez les métadonnées en utilisant:

(id) metaData: (id) target

Prendre plaisir

  #import  static char const * const kMetaDic = "kMetaDic"; #pragma mark - Getters / Setters - (id)metaData:(id)target { return objc_getAssociatedObject(target, kMetaDic); } - (void)setMetaData:(id)target withObject:(id)newObj { objc_setAssociatedObject(target, kMetaDic, newObj, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } #On the cell constructor - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { .... cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; .... [btnSocial addTarget:self action:@selector(openComments:) forControlEvents:UIControlEventTouchUpInside]; #add the indexpath here or another object [self setMetaData:btnSocial withObject:indexPath]; .... } #The action after button been press: - (IBAction)openComments:(UIButton*)sender{ NSIndexPath *indexPath = [self metaData:sender]; NSLog(@"indexPath: %d", indexPath.row); //Reuse your indexpath Now } 
 func buttonAction(sender:UIButton!) { var position: CGPoint = sender.convertPoint(CGPointZero, toView: self.tablevw) let indexPath = self.tablevw.indexPathForRowAtPoint(position) let cell: TableViewCell = tablevw.cellForRowAtIndexPath(indexPath!) as TableViewCell println(indexPath?.row) println("Button tapped") } 

La réponse de @Vladimir est Swift:

 var buttonPosition = sender.convertPoint(CGPointZero, toView: self.tableView) var indexPath = self.tableView.indexPathForRowAtPoint(buttonPosition)! 

Bien que la recherche de indexPath != nil me donne le doigt … “NSIndexPath n’est pas un sous-type de NSSsortingng”

J’utiliserais la propriété tag comme vous l’avez dit, en définissant l’étiquette comme suit:

 [button setTag:indexPath.row]; 

puis obtenir la balise à l’intérieur du boutonPressedAction comme suit:

 ((UIButton *)sender).tag 

Ou

 UIButton *button = (UIButton *)sender; button.tag; 

Bien que j’aime la méthode des balises … si vous ne voulez pas utiliser de balises pour quelque raison que ce soit, vous pouvez créer un membre NSArray de boutons prédéfinis:

 NSArray* buttons ; 

puis créez ces boutons avant de rendre la tableView et placez-les dans le tableau.

Puis à l’intérieur de la tableView:cellForRowAtIndexPath: fonction que vous pouvez faire:

 UIButton* button = [buttons objectAtIndex:[indexPath row] ] ; [cell.contentView addSubview:button]; 

Ensuite, dans le buttonPressedAction: fonction, vous pouvez faire

 - (void)buttonPressedAction:(id)sender { UIButton* button = (UIButton*)sender ; int row = [buttons indexOfObject:button] ; // Do magic } 

POUR GÉRER LES SECTIONS – J’ai stocké le NSIndexPath dans un object UITableViewCell personnalisé

IN CLKIndexPricesHEADERTableViewCell.xib

IN IB Ajouter UIButton à XIB – NE PAS append d’action!

Ajouter un sharepoint vente @property (à retenir, non atomique) IBOutlet UIButton * buttonIndexSectionClose;

NE PAS CTRL + DRAG une action dans IB (faite dans le code ci-dessous)

 @interface CLKIndexPricesHEADERTableViewCell : UITableViewCell ... @property (retain, nonatomic) IBOutlet UIButton *buttonIndexSectionClose; @property (nonatomic, retain) NSIndexPath * indexPathForCell; @end 

Dans viewForHeaderInSection (devrait également fonctionner pour cellForRow …. etc si votre table a seulement 1 section)

 - viewForHeaderInSection is called for each section 1...2...3 - get the cell CLKIndexPricesHEADERTableViewCell - getTableRowHEADER just does the normal dequeueReusableCellWithIdentifier - STORE the indexPath IN the UITableView cell - indexPath.section = (NSInteger)section - indexPath.row = 0 always (we are only interestd in sections) - (UIView *) tableView:(UITableView *)tableView1 viewForHeaderInSection:(NSInteger)section { //Standard method for getting a UITableViewCell CLKIndexPricesHEADERTableViewCell * cellHEADER = [self getTableRowHEADER]; 

… utiliser la section pour obtenir des données pour votre cellule

…Remplissez le

  indexName = ffaIndex.routeCode; indexPrice = ffaIndex.indexValue; // [cellHEADER.buttonIndexSectionClose addTarget:self action:@selector(buttonDELETEINDEXPressedAction:forEvent:) forControlEvents:UIControlEventTouchUpInside]; cellHEADER.indexPathForCell = [NSIndexPath indexPathForRow:0 inSection:section]; return cellHEADER; } 

USER appuie sur le bouton DELETE sur un en-tête de section et cela appelle

 - (void)buttonDELETEINDEXPressedAction:(id)sender forEvent:(UIEvent *)event { NSLog(@"%s", __PRETTY_FUNCTION__); UIView * parent1 = [sender superview]; // UiTableViewCellContentView //UIView *myContentView = (UIView *)parent1; UIView * parent2 = [parent1 superview]; // custom cell containing the content view //UIView * parent3 = [parent2 superview]; // UITableView containing the cell //UIView * parent4 = [parent3 superview]; // UIView containing the table if([parent2 isMemberOfClass:[CLKIndexPricesHEADERTableViewCell class]]){ CLKIndexPricesHEADERTableViewCell *myTableCell = (CLKIndexPricesHEADERTableViewCell *)parent2; //UITableView *myTable = (UITableView *)parent3; //UIView *mainView = (UIView *)parent4; NSLog(@"%s indexPath.section,row[%d,%d]", __PRETTY_FUNCTION__, myTableCell.indexPathForCell.section,myTableCell.indexPathForCell.row); NSSsortingng *key = [self.sortedKeysArray objectAtIndex:myTableCell.indexPathForCell.section]; if(key){ NSLog(@"%s DELETE object at key:%@", __PRETTY_FUNCTION__,key); self.keyForSectionIndexToDelete = key; self.sectionIndexToDelete = myTableCell.indexPathForCell.section; UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Remove Index" message:@"Are you sure" delegate:self cancelButtonTitle:@"No" otherButtonTitles:@"Yes", nil]; alertView.tag = kALERTVIEW_REMOVE_ONE_INDEX; [alertView show]; [alertView release]; //------ }else{ NSLog(@"ERROR: [%s] key is nil for section:%d", __PRETTY_FUNCTION__,myTableCell.indexPathForCell.section); } }else{ NSLog(@"ERROR: [%s] CLKIndexPricesHEADERTableViewCell not found", __PRETTY_FUNCTION__); } } 

Dans cet exemple, j’ai ajouté un bouton Supprimer, il est donc recommandé d’afficher UIAlertView pour le confirmer.

Je stocke la section et la clé dans le dictionnaire stockant des informations sur la section dans un ivar dans le VC

 - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { if(alertView.tag == kALERTVIEW_REMOVE_ONE_INDEX){ if(buttonIndex==0){ //NO NSLog(@"[%s] BUTTON:%d", __PRETTY_FUNCTION__,buttonIndex); //do nothing } else if(buttonIndex==1){ //YES NSLog(@"[%s] BUTTON:%d", __PRETTY_FUNCTION__,buttonIndex); if(self.keyForSectionIndexToDelete != nil){ //Remove the section by key [self.indexPricesDictionary removeObjectForKey:self.keyForSectionIndexToDelete]; //sort the keys so sections appear alphabetically/numbericsearch (minus the one we just removed) [self updateTheSortedKeysArray]; //Delete the section from the table using animation [self.tableView beginUpdates]; [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:self.sectionIndexToDelete] withRowAnimation:UITableViewRowAnimationAutomatic]; [self.tableView endUpdates]; //required to sortinggger refresh of myTableCell.indexPathForCell else old values in UITableViewCells [self.tableView reloadData]; }else{ NSLog(@"ERROR: [%s] OBJECT is nil", __PRETTY_FUNCTION__); } } else { NSLog(@"ERROR: [%s] UNHANDLED BUTTON:%d", __PRETTY_FUNCTION__,buttonIndex); } }else { NSLog(@"ERROR: [%s] unhandled ALERTVIEW TAG:%d", __PRETTY_FUNCTION__,alertView.tag); } } 
 A better way would be to subclass your button and add a indexPath property to it. //Implement a subclass for UIButton. @interface NewButton:UIButton @property(nonatomic, strong) NSIndexPath *indexPath; Make your button of type NewButton in the XIB or in the code whereever you are initializing them. Then in the cellForRowAtIndexPath put the following line of code. button.indexPath = indexPath; return cell; //As usual Now in your IBAction -(IBAction)buttonClicked:(id)sender{ NewButton *button = (NewButton *)sender; //Now access the indexPath by buttons property.. NSIndexPath *indexPath = button.indexPath; //:) } 

Ca marche pour moi aussi, Merci @Cocoanut

J’ai trouvé que la méthode d’utilisation de la superview de la superview pour obtenir une référence à l’indexPath de la cellule fonctionnait parfaitement. Merci à iphonedevbook.com (macnsmith) pour le texte du lien

 -(void)buttonPressed:(id)sender { UITableViewCell *clickedCell = (UITableViewCell *)[[sender superview] superview]; NSIndexPath *clickedButtonPath = [self.tableView indexPathForCell:clickedCell]; ... } 

vous pouvez utiliser le motif de balise:

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSSsortingng *identifier = @"identifier"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; if (cell == nil) { cell = [[UITableView alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]; [cell autorelelase]; UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(10, 5, 40, 20)]; [button addTarget:self action:@selector(buttonPressedAction:) forControlEvents:UIControlEventTouchUpInside]; [button setTag:[indexPath row]]; //use the row as the current tag [cell.contentView addSubview:button]; [button release]; } UIButton *button = (UIButton *)[cell viewWithTag:[indexPath row]]; //use [indexPath row] [button setTitle:@"Edit" forState:UIControlStateNormal]; return cell; } - (void)buttonPressedAction:(id)sender { UIButton *button = (UIButton *)sender; //button.tag has the row number (you can convert it to indexPath) } 

Est-ce que je manque quelque chose? Vous ne pouvez pas simplement utiliser l’expéditeur pour identifier le bouton. L’expéditeur vous donnera des informations comme ceci:

 > 

Ensuite, si vous souhaitez modifier les propriétés du bouton, dites l’image d’arrière-plan que vous venez d’indiquer à l’expéditeur:

 [sender setBackgroundImage:[UIImage imageNamed:@"new-image.png"] forState:UIControlStateNormal]; 

Si vous avez besoin du tag, la méthode d’ACBurk est correcte.

 // how do I know which button sent this message? // processing button press for this row requires an indexPath. 

Assez simple en fait:

 - (void)buttonPressedAction:(id)sender { UIButton *button = (UIButton *)sender; CGPoint rowButtonCenterInTableView = [[rowButton superview] convertPoint:rowButton.center toView:self.tableView]; NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:rowButtonCenterInTableView]; MyTableViewItem *rowItem = [self.itemsArray objectAtIndex:indexPath.row]; // Now you're good to go.. do what the intention of the button is, but with // the context of the "row item" that the button belongs to [self performFooWithItem:rowItem]; } 

Travaille bien pour moi: P

Si vous souhaitez ajuster la configuration de votre action cible, vous pouvez inclure le paramètre d’événement dans la méthode, puis utiliser les touches de cet événement pour résoudre les coordonnées du toucher. Les coordonnées doivent encore être résolues dans les limites de la vue tactile, mais cela peut sembler plus facile pour certaines personnes.

créer un tableau nsmutable et mettre tous les boutons dans ce tableau usint [array addObject: yourButton];

dans la méthode de pression sur le bouton

  (void)buttonPressedAction:(id)sender { UIButton *button = (UIButton *)sender; for(int i=0;i<[yourArray count];i++){ if([buton isEqual:[yourArray objectAtIndex:i]]){ //here write wat u need to do } } 

Une légère variation de Cocoanuts répond (cela m’a aidé à résoudre ce problème) lorsque le bouton se trouvait dans le pied de page d’un tableau (ce qui vous empêche de trouver la cellule cliquée:

 -(IBAction) buttonAction:(id)sender; { id parent1 = [sender superview]; // UiTableViewCellContentView id parent2 = [parent1 superview]; // custom cell containing the content view id parent3 = [parent2 superview]; // UITableView containing the cell id parent4 = [parent3 superview]; // UIView containing the table UIView *myContentView = (UIView *)parent1; UITableViewCell *myTableCell = (UITableViewCell *)parent2; UITableView *myTable = (UITableView *)parent3; UIView *mainView = (UIView *)parent4; CGRect footerViewRect = myTableCell.frame; CGRect rect3 = [myTable convertRect:footerViewRect toView:mainView]; [cc doSomethingOnScreenAtY:rect3.origin.y]; } 

J’utilise toujours des tags.

Vous devez sous- UITableviewCell et gérer le bouton-poussoir à partir de là.

C’est simple; faire une cellule personnalisée et prendre une sortie de bouton

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSSsortingng *identifier = @"identifier"; customCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; cell.yourButton.tag = indexPath.Row; - (void)buttonPressedAction:(id)sender 

changer l’identifiant dans la méthode ci-dessus pour (UIButton *)

Vous pouvez obtenir la valeur de quel bouton est tapé en effectuant sender.tag.

Sous-classe le bouton pour stocker la valeur requirejse, peut-être créer un protocole (ControlWithData ou autre). Définissez la valeur lorsque vous ajoutez le bouton à la cellule de la vue de table. Dans votre événement de retouche, vérifiez si l’expéditeur respecte le protocole et extrait les données. Je stocke normalement une référence à l’object réel rendu sur la cellule de la vue de table.

SWIFT 2 UPDATE

Voici comment trouver le bouton sur lequel vous avez tapé + envoyer des données à un autre ViewController à partir de l’indexPath.row de ce bouton car je suppose que c’est le but pour la plupart!

 @IBAction func yourButton(sender: AnyObject) { var position: CGPoint = sender.convertPoint(CGPointZero, toView: self.tableView) let indexPath = self.tableView.indexPathForRowAtPoint(position) let cell: UITableViewCell = tableView.cellForRowAtIndexPath(indexPath!)! as UITableViewCell print(indexPath?.row) print("Tap tap tap tap") } 

Pour ceux qui utilisent une classe ViewController et ont ajouté une tableView, j’utilise un ViewController au lieu d’un TableViewController. J’ai donc ajouté manuellement la tableView pour y accéder.

Voici le code permettant de transmettre des données à un autre VC lorsque vous appuyez sur ce bouton et que vous transmettez l’ indexPath.row la cellule

 @IBAction func moreInfo(sender: AnyObject) { let yourOtherVC = self.storyboard!.instantiateViewControllerWithIdentifier("yourOtherVC") as! YourOtherVCVIewController var position: CGPoint = sender.convertPoint(CGPointZero, toView: self.tableView) let indexPath = self.tableView.indexPathForRowAtPoint(position) let cell: UITableViewCell = tableView.cellForRowAtIndexPath(indexPath!)! as UITableViewCell print(indexPath?.row) print("Button tapped") yourOtherVC.yourVarName = [self.otherVCVariable[indexPath!.row]] self.presentViewController(yourNewVC, animated: true, completion: nil) } 

Notez ici que j’utilise une cellule personnalisée ce code fonctionne parfaitement pour moi

  @IBAction func call(sender: UIButton) { var contentView = sender.superview; var cell = contentView?.superview as EmployeeListCustomCell if (!(cell.isKindOfClass(EmployeeListCustomCell))) { cell = (contentView?.superview)?.superview as EmployeeListCustomCell } let phone = cell.lblDescriptionText.text! //let phone = detailObject!.mobile! let url:NSURL = NSURL(ssortingng:"tel://"+phone)!; UIApplication.sharedApplication().openURL(url); } 

La solution de Chris Schwerdt mais ensuite à Swift a fonctionné pour moi:

 @IBAction func rateButtonTapped(sender: UIButton) { let buttonPosition : CGPoint = sender.convertPoint(CGPointZero, toView: self.ratingTableView) let indexPath : NSIndexPath = self.ratingTableView.indexPathForRowAtPoint(buttonPosition)! print(sender.tag) print(indexPath.row) } 

Ce problème comporte deux parties:

1) Obtenir le chemin d’ UITableViewCell de UITableViewCell qui contient UIButton pressé

Il y a quelques suggestions comme:

  • Mise à jour de la tag UIButton dans cellForRowAtIndexPath: méthode utilisant la valeur de row du chemin d’index. Ce n’est pas une bonne solution car elle nécessite une mise à jour continue de la tag et ne fonctionne pas avec les vues de table comportant plusieurs sections.

  • Ajout d’une propriété NSIndexPath à une cellule personnalisée et mise à jour à la place de la tag UIButton dans la méthode cellForRowAtIndexPath: Cela résout le problème de plusieurs sections mais n’est toujours pas bon car il nécessite toujours une mise à jour.

  • Garder une référence faible à UITableView parent dans la cellule personnalisée lors de sa création et en utilisant la méthode indexPathForCell: pour obtenir le chemin d’index. Semble un peu mieux, pas besoin de mettre à jour quoi que ce soit dans la méthode cellForRowAtIndexPath: mais nécessite toujours de définir une référence faible lorsque la cellule personnalisée est créée.

  • Utiliser la propriété superView la cellule pour obtenir une référence au parent UITableView . Pas besoin d’append de propriétés à la cellule personnalisée, et pas besoin de définir / mettre à jour quoi que ce soit à la création / plus tard. Mais la superViewsuperView la superView dépend des détails de l’implémentation iOS. Donc, il ne peut pas être utilisé directement.

Mais cela peut être réalisé en utilisant une simple boucle, car nous sums sûrs que la cellule en question doit être dans une UITableView:

 UIView* view = self; while (view && ![view isKindOfClass:UITableView.class]) view = view.superview; UITableView* parentTableView = (UITableView*)view; 

Ainsi, ces suggestions peuvent être combinées en une méthode de cellule personnalisée simple et sûre pour obtenir le chemin d’index:

 - (NSIndexPath *)indexPath { UIView* view = self; while (view && ![view isKindOfClass:UITableView.class]) view = view.superview; return [(UITableView*)view indexPathForCell:self]; } 

A partir de maintenant, cette méthode peut être utilisée pour détecter quel UIButton est pressé.

2) Informer les autres parties de l’événement presse

Après avoir appris en interne quelle UIButton est pressée dans quelle cellule personnalisée avec le chemin d’ UITableView exact, ces informations doivent être envoyées à d’autres parties (probablement le contrôleur de vue gérant l’ UITableView ). Ainsi, cet événement de clic de bouton peut être géré dans un niveau d’abstraction et de logique similaire à didSelectRowAtIndexPath: de didSelectRowAtIndexPath: méthode du délégué UITableView.

Deux approches peuvent être utilisées pour cela:

a) Délégation: la cellule personnalisée peut avoir une propriété de delegate et peut définir un protocole. Lorsque le bouton est pressé, il exécute simplement ses méthodes de délégation sur sa propriété delegate . Mais cette propriété de delegate doit être définie pour chaque cellule personnalisée lors de leur création. En guise d’alternative, la cellule personnalisée peut également choisir d’exécuter ses méthodes de délégation sur le delegate sa vue de table parent.

b) Centre de notification: les cellules personnalisées peuvent définir un nom de notification personnalisé et publier cette notification avec les informations de chemin d’index et de vue de table parent fournies dans l’object userInfo . Pas besoin de définir quoi que ce soit pour chaque cellule, il suffit d’append un observateur pour la notification de la cellule personnalisée.

J’utilise une solution qui sous-classe UIButton et je pensais que je devais juste la partager ici, les codes dans Swift:

 class ButtonWithIndexPath : UIButton { var indexPath:IndexPath? } 

Ensuite, n’oubliez pas de mettre à jour son indexPath dans cellForRow(at:)

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let returnCell = tableView.dequeueReusableCell(withIdentifier: "cellWithButton", for: indexPath) as! cellWithButton ... returnCell.button.indexPath = IndexPath returnCell.button.addTarget(self, action:#selector(cellButtonPressed(_:)), for: .touchUpInside) return returnCell } 

Ainsi, lorsque vous répondez à l’événement du bouton, vous pouvez l’utiliser comme

 func cellButtonPressed(_ sender:UIButton) { if sender is ButtonWithIndexPath { let button = sender as! ButtonWithIndexPath print(button.indexPath) } } 

Avec Swift 4.2 et iOS 12, UITableView a une méthode appelée indexPathForRow(at:) . indexPathForRow(at:) a la déclaration suivante:

 func indexPathForRow(at point: CGPoint) -> IndexPath? 

Retourne un chemin d’index identifiant la ligne et la section au point donné.


Le code complet suivant montre comment implémenter indexPathForRow(at:) pour obtenir le IndexPath correspondant à partir d’un UIButton situé dans un UITableViewCell :

 import UIKit class CustomCell: UITableViewCell { let button = UIButton(type: .system) override init(style: UITableViewCellStyle, reuseIdentifier: Ssortingng?) { super.init(style: style, reuseIdentifier: reuseIdentifier) button.setTitle("Tap", for: .normal) contentView.addSubview(button) button.translatesAutoresizingMaskIntoConstraints = false button.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true button.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true button.topAnchor.constraintEqualToSystemSpacingBelow(contentView.topAnchor, multiplier: 1).isActive = true button.leadingAnchor.constraintGreaterThanOrEqualToSystemSpacingAfter(contentView.leadingAnchor, multiplier: 1).isActive = true } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } } 
 import UIKit class TableViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() tableView.register(CustomCell.self, forCellReuseIdentifier: "Cell") } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 3 } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomCell cell.button.addTarget(self, action: #selector(printIndexPath), for: .touchUpInside) return cell } @objc func printIndexPath(_ sender: UIButton) { let point = sender.convert(CGPoint.zero, to: tableView) guard let indexPath = tableView.indexPathForRow(at: point) else { return } print(indexPath) } }