UITableView多项选择

时间:2010-06-14 21:02:20

标签: iphone uitableview

如何在我的基于视图的应用程序中添加UITableView,用户将点击多个单元格,它将被选中,就像时钟应用程序的“新警报”设置名为“重复”(时钟>警报> ; +>重复),如何获取数组中的所有选定单元格?

11 个答案:

答案 0 :(得分:124)

要进行多项选择,请在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 }

答案 1 :(得分:28)

-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;
    }
}

除了单元格自己的附件类型状态之外,您可以维护一组选定状态,或者在表格视图中迭代查询每个状态的单元格,以便读出所选行。

答案 2 :(得分:18)

@BrendanBreg implementation对我不起作用。 @RaphaelOliveira提供了good solution,但是当您向下滚动表格时 - 选择了错误的行(因为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;
    }
}

答案 3 :(得分:15)

self.tableView.allowsMultipleSelection = YES;

答案 4 :(得分:14)

除了上面的答案之外,还有一个快速的提示:模仿来自时钟应用程序的Apple风格(在检查/取消选中行后使行选择颜色淡出),将其添加到{{ 1}},在条件之后:

didSelectRowAtIndexPath

来自Apple的TableMultiSelect指南。

答案 5 :(得分:5)

答案 6 :(得分:3)

我见过很多开发人员的这个问题。由于表格视图重新使用单元格的性质,它删除或随意检查。我为此创建了一个有效的解决方案。从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

答案 7 :(得分:1)

时钟报警重复表视图不是多重选择。把它想象成一个复选框。

选择单元格后,将更改字体颜色和附件类型,并且选择将淡出。选中已选中的单元格后,将更改字体颜色和附件类型,并且选择将淡出。

在didSelectRowAtIndexPath委托方法中,您可以为所选单元格设置文本颜色和附件类型,然后取消选择单元格。您还可以在数据模型中记录新状态。这可能就像表示所选状态的位掩码一样简单,但取决于您显示的数据。

在您的cellForRowAtIndexPath:dataSource方法中,根据您的数据模型设置文本颜色和配件类型。

实际的多重选择将是类似的。您必须跟踪选择的单元格,并在创建或显示每个状态时设置所选单元格。当表视图报告选择了单元格时,切换数据模型中的选择状态并相应地设置单元格的选定状态。

答案 8 :(得分:1)

您无法关闭indexPath,因为引用的单元格会随着scoll而变化。将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;
}

答案 9 :(得分:1)

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
}

答案 10 :(得分:0)

我知道这是一个过时的帖子,但是为了将来使用,以下代码将解决确保在滚动过程中仅在选中的行上显示选中标记的问题:

override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    cell.accessoryType = (cell.isSelected) ? .checkmark : .none
}