Подтвердить что ты не робот

Как узнать номер строки UITableview

У меня есть UITableViewCell с UISwitch как вспомогательный вид каждой ячейки. Когда я изменяю значение переключателя в ячейке, как я могу узнать, в какой строке находится переключатель? Мне нужно номер строки в событии, измененном значением переключателя.

4b9b3361

Ответ 1

Тэги, подклассы или иерархия иерархии представлений работают слишком много!. Сделайте это в своем методе действий:

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

Работает с любыми типами представлений, таблицами нескольких секций, что бы вы ни выбрали - пока источник отправителя находится внутри рамки ячейки (спасибо rob!), что обычно будет иметь место.

И вот это расширение UITableView Swift:

extension UITableView {
    func indexPath(for view: UIView) -> IndexPath? {
        let location = view.convert(CGPoint.zero, to: self)
        return self.indexPathForRow(at: location)
    }
}

Ответ 2

Если вы установите для свойства tag номер строки (как предложено другими ответами), вы должны обновлять его каждый раз в tableView:cellForRowAtIndexPath: (поскольку ячейку можно повторно использовать для разных строк).

Вместо этого, когда вам нужен номер строки, вы можете пройти цепочку superview из UISwitch (или любого другого вида) в UITableViewCell, а затем в UITableView и спросить таблицу просмотр для пути индекса ячейки:

static NSIndexPath *indexPathForView(UIView *view) {
    while (view && ![view isKindOfClass:[UITableViewCell class]])
        view = view.superview;
    if (!view)
        return nil;
    UITableViewCell *cell = (UITableViewCell *)view;
    while (view && ![view isKindOfClass:[UITableView class]])
        view = view.superview;
    if (!view)
        return nil;
    UITableView *tableView = (UITableView *)view;
    return [tableView indexPathForCell:cell];
}

Это не требует ничего в tableView:cellForRowAtIndexPath:.

Ответ 3

в cellForRowAtIndexPath:, установите для свойства tag вашего элемента управления значение indexPath.row

Ответ 4

Я предпочитаю использовать subviews, если вы знаете свой макет, он обычно супер простой и 1 строка короткая...

    NSIndexPath *indexPath = [tableView indexPathForCell:(UITableViewCell *)[[sender superview] superview]];

Это означает, что если он больше вложен, добавьте больше супервидов.

Бит больше информации:

все, что вы делаете, это запрос родительского представления и его родительского представления, которое является ячейкой. Затем вы запрашиваете свой tableview для указательного пути той ячейки, которую вы только что получили.

Ответ 5

Принятое решение - умный хак.

Однако зачем нам использовать hitpoint, если мы можем использовать уже имеющееся свойство tag в UIView? Вы могли бы сказать, что тег может хранить только строку или раздел, так как его единственный Int.

Ну... Не забывайте своих корней ребята (CS101). Единственный Int может хранить два целых числа с двумя меньшими размерами. И вот расширение для этого:

extension Int {

    public init(indexPath: IndexPath) {
        var marshalledInt: UInt32 = 0xffffffff

        let rowPiece = UInt16(indexPath.row)
        let sectionPiece = UInt16(indexPath.section)
        marshalledInt = marshalledInt & (UInt32(rowPiece) << 16)
        marshalledInt = marshalledInt + UInt32(sectionPiece)

        self.init(bitPattern: UInt(marshalledInt))
    }

    var indexPathRepresentation: IndexPath {
        let section = self & 0x0000ffff

        let pattern: UInt32 = 0xffff0000
        let row = (UInt32(self) & pattern) >> 16
        return IndexPath(row: Int(row), section: Int(section))
    }
}

В tableView(_:, cellForRowAt:) вы можете:

cell.yourSwitch.tag = Int(indexPath: indexPath)

И затем в обработчике действий вы можете:

func didToogle(sender: UISwitch){
    print(sender.tag.indexPathRepresentation)
}

Однако учтите это ограничение: строка и раздел должны быть не большими, чем 65535. (UInt16.max)

Я сомневаюсь, что ваши индексы tableView будут такими высокими, но в случае их возникновения, бросить вызов себе и реализовать более эффективную схему упаковки. Скажем, если у нас есть очень маленький раздел, нам не нужны все 16 бит для представления раздела. У нас может быть наш внутренний макет, например:

{section area length}{all remaining}[4 BITS: section area length - 1]

то есть наши 4 LSBs указывают длину области раздела - 1, учитывая, что мы выделяем по крайней мере 1 бит для раздела. Таким образом, в случае, если наш раздел равен 0, строка может занимать до 27 бит ([1] [27] [4]), что определенно должно быть достаточно.

Ответ 6

Один из распространенных способов сделать это - установить tag элемента управления (в вашем случае переключатель) на то, что может использоваться для идентификации строки или представляемого объекта.

Например, в tableView:cellForRowAtIndexPath: установите свойство tag этого переключателя на indexPath.row, а в методе действий вы можете получить тег от отправителя.

Лично мне не нравится этот подход и предпочитаю подклассифицировать UITableViewCell. Кроме того, может быть хорошей идеей добавить "смещение" к тегу, чтобы предотвратить конфликты с тегами других представлений.

Ответ 7

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

- (NSIndexPath *)indexPathForView:(UIView *)view inTableView:(UITableView *)tableView {
    while (view && ![view isKindOfClass:[UITableViewCell class]])
        view = view.superview;
    UITableViewCell *cell = (UITableViewCell *)view;
    return [tableView indexPathForCell:cell];
}

Некоторые утверждают, что этот подход содержит слишком много вычислительной работы из-за цикла while. Альтернатива, преобразует начало представления в пространство координат таблицы и вызывает indexPathForRowAtPoint:, скрывает еще большую работу.

Некоторые утверждают, что этот подход небезопасен относительно возможных изменений SDK. Фактически, Apple уже изменила иерархию ячеек таблицы, добавив в ячейку contentView. Этот подход работает до и после такого изменения. До тех пор, пока предки могут быть найдены через цепочку супервизоров (что так же важно, как и все в UIKit), это хороший код.

Ответ 8

Коллега предложил следующее, которое я сделал в категории UITableView:

+(UITableViewCell*)findParentCellForSubview:(UIView*)view
{
    while (([view isKindOfClass:[UITableViewCell class]] == NO) && ([view superview] != nil))
        view = [view superview];

    if ([view superview] != nil)
        return (UITableViewCell*)view;

    return nil;
}

Все еще взломанно - но он работает.

Ответ 9

Еще один вариант использования супервизора. Работает как категория для UIView.

- (UITableViewCell *)superCell
{
    if (!self.superview) {
        return nil;
    }

    if ([self.superview isKindOfClass:[UITableViewCell class]]) {
        return (UITableViewCell *)self.superview;
    }

    return [self.superview superCell];
}

Ответ 10

Я не знаю о нескольких разделах, но могу дать вам один раздел...

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger index=indexPath.row;
NSString *string=[[NSString alloc]initWithFormat:@"%ld",(long)index];
}

из этого вы можете получить номер строки, и вы можете сохранить его в строке....