UITableView для отмены выбора ячейки

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

Я не могу найти ни одного из звонков делегатов. Есть идеи, как это реализовать? Это действительно будет признак распознавания жестов?

Ответ 1

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

Кажется, это невозможно, и я пошел с распознающим жестом ячейки, чтобы вручную установить выбранное/невыбранное состояние.

Ответ 2

Фактически вы можете сделать это с помощью метода делегата willSelectRowAtIndexPath:

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if ([cell isSelected]) {
        // Deselect manually.
        [tableView.delegate tableView:tableView willDeselectRowAtIndexPath:indexPath];
        [tableView deselectRowAtIndexPath:indexPath animated:YES];
        [tableView.delegate tableView:tableView didDeselectRowAtIndexPath:indexPath];

        return nil;
    }

    return indexPath;
}

Обратите внимание, что deselectRowAtIndexPath: не будет автоматически вызывать методы делегата, поэтому вам нужно сделать эти вызовы вручную.

Ответ 3

в Swift 4:

func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {

    if let indexPathForSelectedRow = tableView.indexPathForSelectedRow,
        indexPathForSelectedRow == indexPath {
        tableView.deselectRow(at: indexPath, animated: false)
        return nil
    }
    return indexPath
}

Ответ 4

При использовании режима "Множественный выбор" "didSelectRowAtIndexPath" не будет вызываться, когда вы нажмете уже выбранную строку. В режиме "Единый выбор" программно можно выбрать более одной строки, и строки будут вызывать didSelectRowAtIndexPath для всех кликов.

Просто голова к любому, у кого были те же проблемы.

Ответ 5

Вот еще более чистое решение:

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if ([[tableView indexPathForSelectedRow] isEqual:indexPath]) {
        [tableView deselectRowAtIndexPath:indexPath animated:YES];
        return nil;
    }
    return indexPath;
}

Ответ 6

Я думаю, что использование синей цветовой гаммы для переключения может дать странное впечатление. Почему бы не использовать аксессуар, как галочку? Это гораздо более знакомая техника для переключения выбора (будь то многоячеечная или одноячеечная).

Смотрите этот ответ для информации: Множественный выбор UITableView

Ответ 7

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if ([cell isSelected]) {
        // Deselect manually.
        if ([tableView.delegate respondsToSelector:@selector(tableView:willDeselectRowAtIndexPath:)]) {
            [tableView.delegate tableView:tableView willDeselectRowAtIndexPath:indexPath];
        }
        [tableView deselectRowAtIndexPath:indexPath animated:YES];
        if ([tableView.delegate respondsToSelector:@selector(tableView:didDeselectRowAtIndexPath:)]) {
            [tableView.delegate tableView:tableView didDeselectRowAtIndexPath:indexPath];
        }
        return nil;
    }

    return indexPath;
}

Ответ 8

Когда вы выбираете ячейку, этот метод делегата запускается.

- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{


        UITableViewCell *theUITableViewCell = [tableView cellForRowAtIndexPath:path];
        if (theUITableViewCell.selected == YES){
            self.tableView deselectRowAtIndexPath:<#(NSIndexPath *)#> animated:<#(BOOL)#>
            // Do more thing
        }else{
            // By default, it is highlighted for selected state
        }

 }

Это псевдокод.

Ответ 9

Вы можете попробовать это, он работает для меня (для одного выбора или нескольких выборов):

а. выделить частный NSMutableArray в viewDidLoad как:

@interface XXXViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
{
    NSMutableArray * selectedZoneCellIndexPaths;
}


- (void)viewDidLoad
{
    selectedZoneCellIndexPaths = [[NSMutableArray alloc] init];
}

В. в UITableViewDelegate didSelectRow добавить следующие строки

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{

     for (NSIndexPath * iter in selectedZoneCellIndexPaths)
     {
         if (indexPath.section == iter.section && indexPath.row == iter.row)
         {
             [tableView deselectRowAtIndexPath:indexPath animated:YES];
             [selectedZoneCellIndexPaths removeObject:iter];
             return;
         }
     }
     [selectedZoneCellIndexPaths addObject:indexPath];
     return;
}

Ответ 10

Быстрая версия ответа заключенного:

public func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? {
  let cell = tableView.cellForRowAtIndexPath(indexPath)
  if (cell?.selected ?? false) {
    // Deselect manually.
    tableView.delegate!.tableView?(tableView, willDeselectRowAtIndexPath: indexPath)
    tableView.deselectRowAtIndexPath(indexPath, animated: true)
    tableView.delegate!.tableView?(tableView, didDeselectRowAtIndexPath: indexPath)
    return nil
  }
return indexPath;
}

Ответ 11

От @prisonerjohn, если кто-то задается вопросом, как проверить, отвечает ли делегат на селектор, как сказал @Patrick, в Swift 3:

override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
    guard let cell = tableView.cellForRow(at: indexPath) else {
        // Handle invalid cell
        ...
    }

    if cell.isSelected {
        if let respond = tableView.delegate?.responds(
            to: #selector(tableView(_:willDeselectRowAt:))),
            respond == true {
            tableView.delegate?.tableView!(tableView, willDeselectRowAt: indexPath)
        }

        tableView.deselectRow(at: indexPath, animated: true)

        if let respond = tableView.delegate?.responds(
            to: #selector(tableView(_:didDeselectRowAt:))),
            respond == true {
            tableView.delegate?.tableView!(tableView, didDeselectRowAt: indexPath)
        }

        return nil
    }

    return indexPath
}

Ответ 12

Оставьте режим одиночного выбора включенным, но переопределите следующие функции следующим образом:

override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
    if tableView.indexPathsForSelectedRows?.contains(indexPath) ?? false {
       tableView.deselectRow(at: indexPath, animated: true)
       return nil
    }

    return indexPath
}

override func tableView(_ tableView: UITableView, willDeselectRowAt indexPath: IndexPath) -> IndexPath? {
    return nil
}

Ответ 13

Я был за тем же, но @occulus 'answer предоставил мне подсказку, которую мне не хватало.

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

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

Ответ 14

В Swift 5:

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{

    let cell = self.tableView.cellForRow(at: indexPath)
    if cell?.accessoryType == UITableViewCell.AccessoryType.checkmark
    {
        cell?.accessoryType = UITableViewCell.AccessoryType.none
        tableView.deselectRow(at: indexPath, animated: true)
    }else
    {
        cell?.selectionStyle = UITableViewCell.SelectionStyle.none
        cell?.accessoryType = UITableViewCell.AccessoryType.checkmark
    }


}