UITableView множественный выбор - PullRequest
42 голосов
/ 15 июня 2010

Как я могу добавить UITableView в мое приложение View-Based, где пользователь будет нажимать на более чем одну ячейку, и он станет выбран, точно так же, как параметр «Новый будильник» в приложении «Часы» с именем «Повторить» (Clock> Alarms) > +> Повторить), и как я могу получить все выбранные ячейки в массиве?

Ответы [ 10 ]

125 голосов
/ 12 декабря 2012

Для множественного выбора добавьте строку ниже в viewDidLoad()

tableView.allowsMultipleSelection = true

Настроить каждый cell после снятия (или инициализации) его в tableView(_:cellForRowAt:)

let selectedIndexPaths = tableView.indexPathsForSelectedRows
let rowIsSelected = selectedIndexPaths != nil && selectedIndexPaths!.contains(indexPath)
cell.accessoryType = rowIsSelected ? .checkmark : .none
// cell.accessoryView.hidden = !rowIsSelected // if using a custom image

Обновлять каждую ячейку, когда она выбрана / снята

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let cell = tableView.cellForRow(at: indexPath)!
    cell.accessoryType = .checkmark
    // cell.accessoryView.hidden = false // if using a custom image
}

override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
    let cell = tableView.cellForRow(at: indexPath)!
    cell.accessoryType = .none
    // cell.accessoryView.hidden = true  // if using a custom image
}

Когда вы закончите, получите массив всех выбранных строк

let selectedRows = tableView.indexPathsForSelectedRows

и получить выбранные данные, где dataArray отображается на строки табличного представления только с 1 секцией

let selectedData = selectedRows?.map { dataArray[$0.row].ID }
28 голосов
/ 15 июня 2010

В вашей реализации -tableView:didSelectRowAtIndexPath: вы бы задали свойство accessoryType ячейки табличного представления в зависимости от ее текущего значения (чтобы оно включалось и выключалось несколькими касаниями).Например:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)path {
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:path];

    if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
        cell.accessoryType = UITableViewCellAccessoryNone;
    } else {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
    }
}

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

18 голосов
/ 29 мая 2013

@ BrendanBreg реализация у меня не сработала. @RaphaelOliveira предоставила хорошее решение , но когда вы прокручиваете свою таблицу вниз - выбираются неправильные строки (потому что UITableView кэширует его ячейки). Итак, я немного изменил решение Рафаэля:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
    cell.accessoryType = UITableViewCellAccessoryCheckmark;
}

- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
    cell.accessoryType = UITableViewCellAccessoryNone;
}

/*Here is modified part*/

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    /*
    ...
    Your implementation stays here
    we're just adding few lines to make sure
    that only correct rows will be selected
    */

    if([[tableView indexPathsForSelectedRows] containsObject:indexPath]) {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
    } else {
        cell.accessoryType = UITableViewCellAccessoryNone;
    }
}
15 голосов
/ 02 апреля 2012
self.tableView.allowsMultipleSelection = YES;
14 голосов
/ 31 января 2012

Просто быстрый совет в дополнение к хорошему ответу, приведенному выше: чтобы имитировать стиль Apple из приложения с часами (заставляя строку выбирать цвет исчезать после проверки / снятия флажка строки), добавьте это к didSelectRowAtIndexPath, после условный:

[self.tableView deselectRowAtIndexPath:indexPath animated:YES];

Из руководства Apple TableMultiSelect .

5 голосов
/ 22 марта 2012
3 голосов
/ 05 апреля 2016

Я видел эту проблему со многими разработчиками. Из-за характера повторного использования ячейки табличного представления он удаляет или случайно проверяет. Я создал рабочее решение для этого. Клонировать / загрузить код из DevelopmentSupportWorkspace и выполнить оттуда проект UITableViewTest.

Вот пример кода для этого:

@interface CheckBoxTestTableViewController ()

@property (nonatomic, strong) NSArray *dataArray;
@property (nonatomic, strong) NSMutableDictionary *selectedIndexDictionary;

@end

@implementation CheckBoxTestTableViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // Uncomment the following line to preserve selection between presentations.
    // self.clearsSelectionOnViewWillAppear = NO;

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem;

    //
    _dataArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"ImageList" ofType:@"plist"]];
    _selectedIndexDictionary = [NSMutableDictionary dictionary];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return _dataArray.count;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"checkMarkCell" forIndexPath:indexPath];
    cell.accessoryType = UITableViewCellAccessoryNone;

    // Configure the cell...
    cell.textLabel.text = _dataArray[indexPath.row][@"text"];
    if (_selectedIndexDictionary[indexPath] != nil) cell.accessoryType = UITableViewCellAccessoryCheckmark;

    return cell;
}

- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
    if (_selectedIndexDictionary[indexPath] == nil) {
        [_selectedIndexDictionary setObject:_dataArray[indexPath.row] forKey:indexPath];
        [[tableView cellForRowAtIndexPath:indexPath] setAccessoryType:UITableViewCellAccessoryCheckmark];
    }else{
        [_selectedIndexDictionary removeObjectForKey:indexPath];
        [[tableView cellForRowAtIndexPath:indexPath] setAccessoryType:UITableViewCellAccessoryNone];
    }
//    [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
@end
1 голос
/ 24 августа 2016

1 - Разрешить множественный выбор и переключение выбранного состояния:

tableView.allowsMultipleSelection = true

2 - собрать или получить массив всех выбранных индексов, когда вы закончите:

let selected = tableView.indexPathsForSelectedRows

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

3 - Изменение внешнего вида ячейки в зависимости от выбранного состояния: переопределите этот метод в своем подклассе UITableViewCell. Если у вас нет подкласса, создайте его.

// In UITableViewCell subclass
override func setSelected(selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)
    accessoryType = selected ? .Checkmark : .None
}
1 голос
/ 03 июля 2013

Вы не можете отключить indexPath, потому что ячейки, которые ссылаются на вас, изменяются при прокрутке. Поместите NSLog в cellForRowAtIndexPath, чтобы увидеть это. Вы можете сделать проверку / снять галочку в willSelectRowAtIndexPath или didSelectRowAtIndexPath. Это охватывает только начальную проверку или снятие отметки, и также будет иметь вещи, которые будут проверены после прокрутки, потому что базовая ячейка для данного indexPath изменяется.

Таким образом, решение, которое я нашел, состоит в том, чтобы иметь массив выбранных вещей с чем-то, что является специфическим для данной ячейки, и выполнить первоначальную проверку.

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];

  if (![selectedIndexes containsObject:cell.textLabel.text]){
    [selectedIndexes addObject:cell.textLabel.text];
    cell.accessoryType = UITableViewCellAccessoryCheckmark;
  } else {
    [selectedIndexes removeObject:cell.textLabel.text];
    cell.accessoryType = UITableViewCellAccessoryNone;
  }

  return indexPath;
}

Вы также должны иметь логику в cellForRowAtIndexPath, чтобы убедиться, что проверены правильные вещи или нет, когда прокручивается представление:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

  ...

  cell.accessoryType = UITableViewCellAccessoryNone;
  if ([selectedIndexes containsObject:cell.textLabel.text]) {
    cell.accessoryType = UITableViewCellAccessoryCheckmark;
    [cell setSelected:YES animated:YES];
  }

  return cell;
}
1 голос
/ 15 июня 2010

Просмотр таблицы повторений сигналов часов не является множественным выбором.Думайте об этом как о включенных флажках.

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

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

В вашем методе cellForRowAtIndexPath: dataSource установите цвет текста и тип аксессуара на основе вашей модели данных.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...