Множественный выбор UITableView

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

В вашей реализации -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; } } 

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

Для множественного выбора добавьте строку ниже в 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 } 

Реализация @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; } } 
 self.tableView.allowsMultipleSelection = YES; 

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

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

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

Я видел эту проблему со многими разработчиками. Из-за того, что элемент таблицы повторного использования в табличном виде устраняет или не проверяет чеки. Я создал для этого рабочее решение. Клонировать / загрузить код из DevelopmentSupportWorkspace и UITableViewTest проект 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 

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

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

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

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

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

Вы не можете отменить indexPath, потому что ячейки, которые ссылаются на изменения, как вы scoll. Поместите NSLog в cellForRowAtIndexPath, чтобы это увидеть. Вы можете выполнить check / uncheck в файле 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 – Разрешить множественный выбор и переключать выбранное состояние:

 tableView.allowsMultipleSelection = true 

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

 let selected = tableView.indexPathsForSelectedRows 

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

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

 // In UITableViewCell subclass override func setSelected(selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) accessoryType = selected ? .Checkmark : .None } 
Interesting Posts
Давайте будем гением компьютера.