Obtendo linha de célula UITableView ao pressionar o botão

84

Eu tenho um controlador tableview que exibe uma linha de células. Cada célula possui 3 botões. Eu numerei as marcas para cada célula como 1,2,3. O problema é que não sei como descobrir em qual célula um botão está sendo pressionado. No momento, só estou obtendo a etiqueta do remetente quando um dos botões é pressionado. Existe uma maneira de obter o número da linha da célula também quando um botão é pressionado?

minimalpop
fonte

Respostas:

278

Você realmente deveria usar este método:

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

Versão Swift:

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

Isso lhe dará a com indexPathbase na posição do botão que foi pressionado. Então, você só ligaria cellForRowAtIndexPathse precisar do celular ou indexPath.rowdo número da linha.

Se você for paranóico, pode verificar if (indexPath) ...antes de usá-lo, para o caso de indexPathnão ser encontrado naquele ponto na visualização da tabela.

Todas as outras respostas provavelmente serão interrompidas se a Apple decidir mudar a estrutura de visualização.

Fui roubado
fonte
8
isso, um milhão de vezes. nenhum dos outros trabalharam, mas esta foi perfeito e, de longe, a solução mais simples
ine
2
Essa resposta funciona porque é a solução correta . Os outros são soluções alternativas. Obrigado!
Bruno Philipe
1
Caso você não tenha self.tableview , consulte minha resposta nesta página.
Ashok
1
Isso funcionou para mim quando percebi que meu remetente era da classe errada. Corrigido para ser o UIButton pressionado, e agora está funcionando!
lordB8r
1
apenas lembre-se de que o método convertPoint:*to*Viewnão é convertPoint:*from*View. Usei o preenchimento automático do Xcode e acabei com o método fromView levando apenas a não funcionar ...
tGilani
40

Edit: Esta resposta está desatualizada. Use este método


Experimente isto:

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

Editar: se você estiver usando contentView, use isso para buttonCell:

UITableViewCell *buttonCell = (UITableViewCell *)senderButton.superview.superview;
user523234
fonte
1
Você não deve adicionar subvisualizações à própria célula, mas apenas à sua contentViewpropriedade - portanto, essa solução realmente não funciona.
1
Estou de acordo com @ H2CO3 e também não acho que isso deva ser feito referenciando superviews. Veja uma maneira melhor abaixo: stackoverflow.com/a/16270198/308315
iwasrobbed
@minimalpop, você pode alterar a resposta correta? para ter um melhor Q / A!
Thomas Besnehard
Isso não funciona no iOS 7. Use indexPathForRowAtPoint: resposta abaixo
Austin
Tentei a mesma versão com um UICollectionView e funciona perfeitamente. Muito obrigado!
Natal
18

Eu recomendaria esta maneira de buscar indexPath da célula que tem qualquer subvisualização personalizada - ( compatível com iOS 7, bem como com todas as versões anteriores )

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

Isso também não exige self.tablview.

Além disso, observe o código comentado, que é útil se você quiser o mesmo por meio de um @selector de UIGestureRecognizer adicionado à sua subvisualização personalizada.

Ashok
fonte
E se eu precisar de dados encontrados no uitableviewcontroller?
iosMentalist
Boa resposta. Se você tem uma barra de pesquisa e gostaria de saber qual tabela é usada no momento, você também pode usá-la.
Suraj K Thomas,
a hierarquia das células da tabela mudou? você pode me ajudar a entender quais mudanças aconteceram e podem ser mudadas ainda mais?
Kamaldeep singh Bhatia
3

Existem duas maneiras:

  1. @ H2CO3 está certo. Você pode fazer o que @ user523234 sugeriu, mas com uma pequena alteração, para respeitar o UITableViewCellContentView que deve vir entre o UIButton e o UITableViewCell. Então, para modificar seu código:

    - (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. Se você criar um UITableViewCell personalizado (sua própria subclasse), poderá simplesmente chamar selfa IBAction. Você pode vincular a função IBAction ao seu botão usando storyboard ou programaticamente ao configurar a célula.

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

Suponho que você adicione botões à célula cellForRowAtIndexPath, então o que eu faria é criar uma subclasse de classe personalizada UIButton, adicionar uma tag chamada rowNumbere anexar esses dados enquanto você adiciona o botão à célula.

Derek Li
fonte
3
Isso é bom, mas não há razão para criar uma subclasse de UIButtonpara isso. tagé uma propriedade comum de UIView.
Rob Napier
Não sei o que eu estava pensando e suponha que algo da IU não é uma IU , obrigado pela correção!
Derek Li
2

Outra maneira simples:

  • Obtenha o ponto de contato em tableView

  • Em seguida, obtenha o caminho do índice da célula no ponto

  • O caminho do índice contém o índice da linha

O código é:

- (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
fonte
1

Swift 3

Nota: Isso realmente deveria ir na resposta aceita acima, exceto que meta desaprova tais edições.

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

Dois pequenos comentários:

  1. A função padrão tem o tipo de remetente Any, que não tem convert.
  2. CGPointZero pode ser substituído por CGPoint ()
Roy Falk
fonte
Funciona perfeitamente.
0

Uma solução poderia ser verificar a tag da supervisão do botão ou até mesmo mais alto na hierarquia de visão (se o botão estiver na visão de conteúdo da célula).

Jakob W
fonte
0

Eu gostaria de compartilhar o código em 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
fonte
0

Rapidamente:

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