Obtenir une ligne de cellule UITableView en appuyant sur un bouton

84

J'ai un contrôleur tableview qui affiche une rangée de cellules. Chaque cellule a 3 boutons. J'ai numéroté les balises pour chaque cellule à 1,2,3. Le problème est que je ne sais pas comment trouver sur quelle cellule un bouton est enfoncé. Je ne reçois actuellement le tag de l'expéditeur que lorsque l'un des boutons a été enfoncé. Existe-t-il également un moyen d'obtenir le numéro de ligne de cellule lorsqu'un bouton est enfoncé?

minimalpop
la source

Réponses:

278

Vous devriez vraiment utiliser cette méthode à la place:

CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition];

Version Swift:

let buttonPosition = sender.convert(CGPoint(), to:tableView)
let indexPath = tableView.indexPathForRow(at:buttonPosition)

Cela vous donnera la indexPathbase sur la position du bouton qui a été enfoncé. Ensuite, vous appelez simplement cellForRowAtIndexPathsi vous avez besoin de la cellule ou indexPath.rowsi vous avez besoin du numéro de ligne.

Si vous êtes paranoïaque, vous pouvez vérifier if (indexPath) ...avant de l'utiliser au cas où le point indexPathne serait pas trouvé sur la vue de table.

Toutes les autres réponses sont susceptibles de casser si Apple décide de modifier la structure de la vue.

J'ai été volé
la source
8
ceci, un million de fois. aucun des autres travaillé, mais c'était parfait et de loin la solution la plus simple
ine
2
Cette réponse fonctionne car c'est la bonne solution. Les autres sont des solutions de contournement. Merci!
Bruno Philipe
1
Si vous n'avez self.tableview , s'il vous plaît se référer à ma réponse sur cette page.
Ashok
1
Cela a fonctionné pour moi une fois que j'ai réalisé que mon expéditeur était la mauvaise classe. Correction du fait que le bouton UIButton était enfoncé, et maintenant cela fonctionne!
lordB8r
1
rappelez-vous simplement que la méthode convertPoint:*to*Viewne l' est pas convertPoint:*from*View. J'ai utilisé la saisie semi-automatique Xcode et je me suis retrouvé avec la méthode fromView, ce qui ne fonctionnait que ...
tGilani
40

Edit: Cette réponse est obsolète. Veuillez utiliser cette méthode à la place


Essaye ça:

-(void)button1Tapped:(id)sender
{
    UIButton *senderButton = (UIButton *)sender;
    UITableViewCell *buttonCell = (UITableViewCell *)[senderButton superview];
    UITableView* table = (UITableView *)[buttonCell superview];
    NSIndexPath* pathOfTheCell = [table indexPathForCell:buttonCell];
    NSInteger rowOfTheCell = [pathOfTheCell row];
    NSLog(@"rowofthecell %d", rowOfTheCell);
}

Modifier: si vous utilisez contentView, utilisez plutôt ceci pour buttonCell:

UITableViewCell *buttonCell = (UITableViewCell *)senderButton.superview.superview;
user523234
la source
1
Vous n'êtes pas censé ajouter des sous-vues à la cellule elle-même mais uniquement à sa contentViewpropriété - cette solution ne fonctionne donc pas vraiment.
1
Je suis d'accord avec @ H2CO3 et je ne pense pas non plus que cela devrait être fait en référençant les superviews. Veuillez voir une meilleure façon ci-dessous: stackoverflow.com/a/16270198/308315
iwasrobbed
@minimalpop pouvez-vous changer la bonne réponse? pour avoir un meilleur Q / R!
Thomas Besnehard
Cela ne fonctionne pas sous iOS 7. Utilisez indexPathForRowAtPoint: réponse ci
Austin
J'ai essayé la même version avec un UICollectionView et fonctionne parfaitement. Merci beaucoup!
Claus
18

Je recommanderais cette façon de récupérer l'indexPath de la cellule qui a une sous-vue personnalisée - ( compatible avec iOS 7 ainsi que toutes les versions précédentes )

-(void)button1Tapped:(id)sender {
//- (void)cellSubviewTapped:(UIGestureRecognizer *)gestureRecognizer {
//    UIView *parentCell = gestureRecognizer.view.superview;
    UIView *parentCell = sender.superview;

    while (![parentCell isKindOfClass:[UITableViewCell class]]) {   // iOS 7 onwards the table cell hierachy has changed.
        parentCell = parentCell.superview;
    }

    UIView *parentView = parentCell.superview;

    while (![parentView isKindOfClass:[UITableView class]]) {   // iOS 7 onwards the table cell hierachy has changed.
        parentView = parentView.superview;
    }


    UITableView *tableView = (UITableView *)parentView;
    NSIndexPath *indexPath = [tableView indexPathForCell:(UITableViewCell *)parentCell];

    NSLog(@"indexPath = %@", indexPath);
}

Cela ne nécessite pas non self.tablviewplus.

Notez également le code commenté qui est utile si vous voulez le même via un @selector de UIGestureRecognizer ajouté à votre sous-vue personnalisée.

Ashok
la source
Et si j'ai besoin de données trouvées dans uitableviewcontroller?
iosMentalist
Bonne réponse. Si vous avez une barre de recherche et souhaitez savoir quelle table est utilisée pour le moment, vous pouvez également l'utiliser.
Suraj K Thomas
la hiérarchie des cellules du tableau a-t-elle changé? pouvez-vous m'aider à comprendre quels changements sont survenus et peuvent-ils être modifiés davantage?
Kamaldeep singh Bhatia le
3

Il y a deux manières:

  1. @ H2CO3 a raison. Vous pouvez faire ce que @ user523234 a suggéré, mais avec une petite modification, pour respecter le UITableViewCellContentView qui doit se trouver entre l'UIButton et l'UITableViewCell. Donc pour modifier son code:

    - (IBAction)button1Tapped:(id)sender
    {
        UIButton *senderButton = (UIButton *)sender;
        UITableViewCellContentView *cellContentView = (UITableViewCellContentView *)senderButton.superview;
        UITableViewCell *tableViewCell = (UITableViewCell *)cellContentView.superview;
        UITableView* tableView = (UITableView *)tableViewCell.superview;
        NSIndexPath* pathOfTheCell = [tableView indexPathForCell:tableViewCell];
        NSInteger rowOfTheCell = pathOfTheCell.row;
        NSLog(@"rowofthecell %d", rowOfTheCell);
    }
    
  2. Si vous créez un UITableViewCell personnalisé (votre propre sous-classe), vous pouvez simplement appeler selfIBAction. Vous pouvez lier la fonction IBAction à votre bouton à l'aide du storyboard ou par programme lorsque vous configurez la cellule.

    - (IBAction)button1Tapped:(id)sender
    {
        UITableView* tableView = (UITableView *)self.superview;
        NSIndexPath* pathOfTheCell = [tableView indexPathForCell:self];
        NSInteger rowOfTheCell = pathOfTheCell.row;
        NSLog(@"rowofthecell %d", rowOfTheCell);
    }
    
M. T
la source
2

Je suppose que vous ajoutez des boutons à la cellule cellForRowAtIndexPath, alors ce que je ferais, c'est créer une sous-classe de classe personnalisée UIButton, ajouter une balise appelée rowNumberet ajouter ces données pendant que vous ajoutez un bouton à la cellule.

Derek Li
la source
3
C'est bien, mais il n'y a aucune raison de créer une sous-classe de UIButtonpour cela. tagest une propriété commune de UIView.
Rob Napier
Je ne sais pas à quoi je pensais et je suppose que quelque chose d' interface utilisateur n'est pas une interface utilisateur , merci pour la correction!
Derek Li
2

Un autre moyen simple:

  • Obtenez le point de contact dans tableView

  • Ensuite, obtenez le chemin d'index de la cellule au point

  • Le chemin de l'index contient l'index de ligne

Le code est:

- (void)buttonTapped:(id)sender {
    UITapGestureRecognizer *tap = (UITapGestureRecognizer *)sender;
    CGPoint point = [tap locationInView:theTableView];

    NSIndexPath *theIndexPath = [theTableView indexPathForRowAtPoint:point];

    NSInteger theRowIndex = theIndexPath.row;
    // do your stuff here
    // ...
}
vietstone
la source
1

Swift 3

Remarque: Cela devrait vraiment aller dans la réponse acceptée ci-dessus, sauf que meta fronce les sourcils sur de telles modifications.

@IBAction func doSomething(_ sender: UIButton) {
   let buttonPosition = sender.convert(CGPoint(), to: tableView)
   let index = tableView.indexPathForRow(at: buttonPosition)
}

Deux commentaires mineurs:

  1. La fonction par défaut a le type d'expéditeur Any, qui n'a pas de conversion.
  2. CGPointZero peut être remplacé par CGPoint ()
Roy Falk
la source
Fonctionne parfaitement.
0

Une solution pourrait être de vérifier la balise de la vue supervisée du bouton ou même plus haut dans la hiérarchie de la vue (si le bouton est dans la vue de contenu de la cellule).

Jakob W
la source
0

Je souhaite partager du code dans Swift -

extension UITableView
{
    func indexPathForCellContainingView(view1:UIView?)->NSIndexPath?
    {
        var view = view1;
        while view != nil {
            if (view?.isKindOfClass(UITableViewCell) == true)
            {
                return self.indexPathForCell(view as! UITableViewCell)!
            }
            else
            {
                view = view?.superview;
            }
        }
        return nil
    }
}
Anupam Mishra
la source
0

En rapide:

@IBAction func buttonAction(_ sender: UIButton) {
    guard let indexPath = tableView.indexPathForRow(at: sender.convert(CGPoint(), to: tableView)) else {
        return
    }
    // do something
}
Leszek Szary
la source