Получение строки ячейки UITableView при нажатии кнопки

84

У меня есть контроллер tableview, который отображает ряд ячеек. В каждой ячейке по 3 кнопки. Я пронумеровал теги для каждой ячейки как 1,2,3. Проблема в том, что я не знаю, как узнать, в какой ячейке нажимается кнопка. В настоящее время я получаю метку отправителя только при нажатии одной из кнопок. Есть ли способ получить номер строки ячейки при нажатии кнопки?

Minimalpop
источник

Ответы:

278

Вместо этого вам действительно стоит использовать этот метод:

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

Быстрая версия:

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

Это даст вам indexPathоснование на позиции нажатой кнопки. Тогда вы просто позвоните, cellForRowAtIndexPathесли вам нужна ячейка или indexPath.rowномер строки.

Если вы параноик, вы можете проверить, if (indexPath) ...прежде чем использовать его, на случай, если indexPathдля этой точки в представлении таблицы не будет найдено.

Все остальные ответы, скорее всего, сломаются, если Apple решит изменить структуру представления.

Меня ограбили
источник
8
это миллион раз. ни один из остальных не работал, но это было прекрасно , и, безусловно , самое простое решение
INE
2
Этот ответ работает, потому что это правильное решение. Остальные - обходные пути. Благодаря!
Бруно Филип
1
В случае , если вы не имеете self.tableview , пожалуйста , обратитесь к моему ответу на этой странице.
Ашок
1
Это сработало для меня, как только я понял, что мой отправитель был неправильным классом. Исправлено нажатие кнопки UIButton, и теперь она работает!
lordB8r
1
просто помните, что метода convertPoint:*to*Viewнет convertPoint:*from*View. Я использовал автозаполнение Xcode и в итоге получил метод fromView, что привело только к тому, что он не работал ...
tGilani
40

Изменить: этот ответ устарел. Пожалуйста, используйте этот метод вместо


Попробуй это:

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

Изменить: если вы используете contentView, используйте это вместо buttonCell:

UITableViewCell *buttonCell = (UITableViewCell *)senderButton.superview.superview;
user523234
источник
1
Вы не должны добавлять подпредставления к самой ячейке, а только к ее contentViewсвойству, поэтому это решение на самом деле не работает.
1
Я согласен с @ H2CO3, и я также не думаю, что это следует делать, ссылаясь на супервизоры. См. Лучший способ ниже: stackoverflow.com/a/16270198/308315
iwasrobbed
@minimalpop, пожалуйста, измените правильный ответ? чтобы получить лучший вопрос / ответ!
Thomas Besnehard
Это не работает в iOS 7. Используйте indexPathForRowAtPoint: ответ ниже
Остин,
Я пробовал ту же версию с UICollectionView и отлично работает. Большое спасибо!
Клаус
18

Я бы порекомендовал этот способ получить indexPath ячейки, которая имеет любое настраиваемое subview - ( совместим с iOS 7, а также со всеми предыдущими версиями )

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

Этого тоже не требуется self.tablview.

Также обратите внимание на закомментированный код, который полезен, если вы хотите, чтобы то же самое через @selector UIGestureRecognizer было добавлено в ваше настраиваемое подвид.

Ашок
источник
Что, если мне нужны данные, найденные в uitableviewcontroller?
iosMentalist
Хороший ответ. Если у вас есть панель поиска и вы хотите знать, какая таблица используется в данный момент, вы также можете использовать ее.
Сурадж К. Томас
иерархия ячеек таблицы изменилась? Можете ли вы помочь мне понять, какие изменения произошли и могут ли они быть изменены в дальнейшем?
Kamaldeep Singh Bhatia
3

Есть два способа:

  1. @ H2CO3 правильно. Вы можете сделать то, что предложил @ user523234, но с небольшими изменениями, чтобы уважать UITableViewCellContentView, который должен находиться между UIButton и UITableViewCell. Итак, чтобы изменить его код:

    - (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. Если вы создаете пользовательский UITableViewCell (ваш собственный подкласс), вы можете просто вызвать selfIBAction. Вы можете связать функцию IBAction со своей кнопкой с помощью раскадровки или программно при настройке ячейки.

    - (IBAction)button1Tapped:(id)sender
    {
        UITableView* tableView = (UITableView *)self.superview;
        NSIndexPath* pathOfTheCell = [tableView indexPathForCell:self];
        NSInteger rowOfTheCell = pathOfTheCell.row;
        NSLog(@"rowofthecell %d", rowOfTheCell);
    }
    
Мистер Т.
источник
2

Я предполагаю, что вы добавляете кнопки в ячейку cellForRowAtIndexPath, тогда я бы создал подкласс настраиваемого класса UIButton, добавил тег с именем rowNumberи добавил эти данные при добавлении кнопки в ячейку.

Дерек Ли
источник
3
Это нормально, но нет причин создавать для этого подкласс UIButton. tagявляется общим свойством UIView.
Роб Напье
Не знаю, о чем я думал, и предполагаю, что пользовательский интерфейс - это не пользовательский интерфейс , спасибо за исправление!
Дерек Ли
2

Другой простой способ:

  • Получите точную информацию в tableView

  • Затем получите индексный путь ячейки в точке

  • Путь к индексу содержит индекс строки

Код такой:

- (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
источник
1

Swift 3

Примечание: это действительно должно быть в принятом ответе выше, за исключением того, что мета не одобряет такие изменения.

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

Два незначительных комментария:

  1. Функция по умолчанию имеет тип отправителя Any, у которого нет convert.
  2. CGPointZero можно заменить на CGPoint ()
Рой Фальк
источник
Прекрасно работает.
0

Одним из решений может быть проверка тега супервизора кнопки или даже выше в иерархии представления (если кнопка находится в представлении содержимого ячейки).

Якоб В
источник
0

Я хотел бы быстро поделиться кодом -

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

Быстро:

@IBAction func buttonAction(_ sender: UIButton) {
    guard let indexPath = tableView.indexPathForRow(at: sender.convert(CGPoint(), to: tableView)) else {
        return
    }
    // do something
}
Leszek Szary
источник