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?

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.


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;

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.


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

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.


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
    // ...
}

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

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).


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

0

Rapidamente:

@IBAction func buttonAction(_ sender: UIButton) {
    guard let indexPath = tableView.indexPathForRow(at: sender.convert(CGPoint(), to: tableView)) else {
        return
    }
    // do something
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.