Як отримати UITableViewCell indexPath з комірки?


75

Як мені, з клітини, отримати його indexPathв UITableView?

Я шукав навколо переповнення стека та google, але вся інформація знаходиться навпаки. Чи є спосіб отримати доступ до superView/, UITableViewа потім шукати комірку?

Більше інформації про контекст: у мене є два класи, один викликається, Cueа другий CueTableCell(що є підкласом UITableViewCell) CueTableCell- це візуальне представлення Cue(обидва класи мають вказівники один на одного). Cueоб'єкти знаходяться у пов'язаному списку, і коли користувач виконує певну команду, потрібно вибрати візуальне представлення (the CueTableCell) наступного Cue. Таким чином, Cueклас викликає selectметод на наступний Cueу списку, який витягує UITableViewз cellі викликає його selectRowAtIndexPath:animated:scrollPosition:, для яких він потребує indexPathз UITableViewCell.


2
Так само, як і ваше інше запитання про отримання UITableViewз клітини - чому? Це здається запахом коду поганого дизайнерського рішення - не так багато законних випадків використання, щоб клітина знала, чи це indexPath, чи є це на екрані чи ні.
Пол.

Я погоджуюсь з коментарем Paul.s. Ви повинні вказати, чому ви хочете це зробити, адже те, що ви намагаєтеся зробити, - це, мабуть, погана ідея.
rdelmar

@ Paul.s Я розмістив дизайн своєї програми у питанні. Це може бути поганою практикою програмування, і в цьому випадку, якщо ви можете запропонувати альтернативу, це було б дуже корисно. Я дуже новачок у какао та відносно новачок у програмуванні загалом.
sinθ

Варто зазначити, що indexPathsForVisibleRows існує - це критично важливо, коли ви хочете знати "де ви знаходитесь" у сувій.
Fattie

Відповіді:


137
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];

Це допомагає прочитати документацію UITableView , навіть якщо це дехто вважає суперечливим (див. Коментарі нижче).

Клітинка не має бізнесу, знаючи, який її шлях до індексу. Контролер повинен містити будь-який код , який маніпулює елементи призначеного для користувача інтерфейсу на основі моделі даних або що дані модифікує на основі взаємодій UI. (Див. MVC .)


41
Корисно, якщо ви прочитаєте питання. Це з UITableViewCell, який не має властивості tableView (і, за всіма переказами, не повинен).
voidref

14
@voidref Це також допомагає подумати над питанням ;-). Клітинка не має бізнесу, знаючи, який її шлях до індексу. Отже, цей код повинен бути в контролері. Довідкові відомості про MVC див. У розділі Основні компетенції какао .
Мунді,

2
Не має значення, чи було це очевидно з самого початку, що людині потрібна правильна відповідь.
jdog

11
Не відповідає на вихідне запитання. Бувають випадки, коли клітина повинна знати свій шлях. Наприклад, якщо ви застосували певну форму дії пальцем до підкласизованої комірки, можливо, вам доведеться повідомити батьківському поданню, яка комірка в даний момент проведена. Одним із способів було б, щоб метод у parentView прокручував клітинки tableView і перевіряв iVar, який був встановлений у комірці. Кращим способом було б отримати клітинку, щоб повідомити parentView, що це indexPath, за допомогою методу делегування ... і, отже, комірка повинна знати, що це indexPath. Тож Мунді, краще відповісти на запитання, а потім висловити свою думку.
wuf810,

4
Шлях індексу є "клеєм" між клітинками та моделлю даних, тому він належить контролеру. Довгий коментар вище фактично неправильний. @ wuf810 ... оскільки контролер знає взаємозв'язок між коміркою та шляхом індексу, комірка цього не робить (і не повинна).
Mundi

24

Спробуйте це з вашого UITableViewCell:

NSIndexPath *indexPath = [(UITableView *)self.superview indexPathForCell: self];

РЕДАГУВАТИ: Здається, це не працює на iOS 8.1.2 і пізніших версіях. Дякую Крісу Принсу за те, що він вказав на це


7
У iOS 8.1.2 супервигляд комірки подання таблиці має тип UITableViewWrapperView. Надзвичайний вигляд - це вид таблиці типів. Але я думаю, що ми тут топчемося на небезпечному ґрунті ...
Кріс Принс

2
Все повертається до "Клітинка не має бізнесу, знаючи, який її шлях до індексу". аргумент. Доступ до Superview - це майже завжди злом, і не дивно, що через деякий час він не працює.
fetuhoku

Абсолютно правильний фатухоку, справа не в клітині, щоб знати шлях індексу
Yahya Alshaar

11

Ви можете спробувати цю просту пораду:

у вашому UITableViewCellкласі:

@property NSInteger myCellIndex; //or add directly your indexPath 

і за вашим cellForRowAtIndexPathметодом:

...
[cell setMyCellIndex : indexPath.row]

тепер ви можете отримати свій індекс клітинки де завгодно


5
Потрібно пам’ятати про оновлення цієї інформації вручну після переупорядкування або видалення комірок.
konrad

10

Для того, щоб звернутися до тих, хто каже "це погана ідея" , у моєму випадку моя потреба в цьому полягає в тому, що на моїй кнопці є кнопка, UITableViewCellяка при натисканні перетворюється на інший погляд. Оскільки це не виділення на самій комірці, [self.tableView indexPathForSelectedRow]це не працює.

Це залишає мені два варіанти:

  1. Збережіть об’єкт, який мені потрібно передати у поданні, у самій комірці таблиці. Хоча це би працювало, це перемогло б мене, NSFetchedResultsControllerоскільки я не хочу зберігати всі об'єкти в пам'яті, особливо якщо таблиця довга.
  2. Витягніть елемент із контролера вибору, використовуючи шлях індексу. Так, здається некрасивим, що мені доводиться розбиратися NSIndexPathшляхом хакерства, але це в кінцевому рахунку дешевше, ніж зберігання об’єктів у пам’яті.

indexPathForCell:є правильним методом для використання, але ось як би я це зробив (цей код передбачається реалізувати в підкласі UITableViewCell:

// uses the indexPathForCell to return the indexPath for itself
- (NSIndexPath *)getIndexPath {
    return [[self getTableView] indexPathForCell:self];
}

// retrieve the table view from self   
- (UITableView *)getTableView {
    // get the superview of this class, note the camel-case V to differentiate
    // from the class' superview property.
    UIView *superView = self.superview;

    /*
      check to see that *superView != nil* (if it is then we've walked up the
      entire chain of views without finding a UITableView object) and whether
      the superView is a UITableView.
    */
    while (superView && ![superView isKindOfClass:[UITableView class]]) {
        superView = superView.superview;
    }

    // if superView != nil, then it means we found the UITableView that contains
    // the cell.
    if (superView) {
        // cast the object and return
        return (UITableView *)superView;
    }

    // we did not find any UITableView
    return nil;
}

PS Мій реальний код дійсно отримує доступ до всього цього з подання таблиці, але я наводжу приклад, чому хтось може захотіти зробити щось подібне безпосередньо в комірці таблиці.


10
  1. Помістіть слабку властивість tableView у файл .h комірки, наприклад:

    @property (weak,nonatomic)UITableView *tableView;

  2. Призначте властивість у методі cellForRowAtIndex, наприклад:

    cell.tableView = tableView;

  3. Тепер, де вам потрібен indexPath комірки:

    NSIndexPath *indexPath = [cell.tableView indexPathForCell:cell];


Це працює, оскільки ми зберігаємо лише вказівник на сам tableView, однак, чи надійний indexPathForCell? Я думав, що це забезпечує лише indexPath видимих ​​комірок ні?
jcpennypincher


4

Відповідь на це питання мені насправді дуже допомогла.

я використав NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];

У senderмоєму випадку це було UITableViewCellі походить від prepareForSegueметоду.

Я використовував це, тому що не мав, TableViewControllerале мавUITableView property outlet

Мені потрібно було з’ясувати заголовок Cellі, отже, потрібно було знати indexPath цього.

Сподіваюся, це комусь допоможе!


4

У iOS 11.0 ви можете використовувати UITableView.indexPathForRow(at point: CGPoint) -> IndexPath?:

if let indexPath = tableView.indexPathForRow(at: cell.center) {
    tableView.selectRow
    (at: indexPath, animated: true, scrollPosition: .middle)
}

Він отримує центральну точку комірки, а потім tableView повертає indexPath, відповідний цій точці.


1

спробуйте це (це працює лише якщо tableView має лише один розділ і всі комірки мають рівні висоти):

//get current cell rectangle relative to its superview
CGRect r = [self convertRect:self.frame toView:self.superview];

//get cell index
int index = r.origin.y / r.size.height;

0

Спробуйте це з вашого UITableViewCell:

NSIndexPath *indexPath = [(UITableView *)self.superview.superview indexPathForCell:self];

-1

Свіфт 4.x

Щоб надати доступ до моєї комірки, я зробив щось подібне:

У мене є розширення UIView:

extension UIView {
    var parentViewController: UIViewController? {
        var parentResponder: UIResponder? = self
        while parentResponder != nil {
            parentResponder = parentResponder!.next
            if let viewController = parentResponder as? UIViewController {
                return viewController
            }
        }
        return nil
    }
}

А потім .. у моєму класі клітини:

class SomeCell: UITableViewCell {

    func someMethod() {
        if let myViewController = self.parentViewController as? CarteleraTableViewController {
            let indexPath : IndexPath = (myViewController.tableView).indexPath(for: self)!
            print(indexPath)
        }
    }
}

Це все формує мене.

З найкращими побажаннями.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.