2010-06-14 45 views
38

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

+0

Psh。我没有看到苹果的例子。 – 2010-06-15 01:03:29

回答

27

在您实施-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; 
    } 
} 

你可以要么保持选择的状态的另外的阵列到细胞自身的附件类型的状态,或在为了读出迭代中对于每个人的状态表视图查询细胞中的选定的行。

+15

这不起作用 - 当选中一个单元格并滚动时,indexPath引用了错误的单元格。因此你会看到多个项目被检查。 – 2013-07-03 19:45:49

+0

与之前的评论一样,这不起作用,因为您将滚动时选择多个项目。 – Siddharth 2014-05-20 20:15:02

+2

-1此解决方案存在问题,一旦您选择某些行并滚动,您可以看到许多复选标记,这些复选标记用于尚未选中的单元格。 – raaz 2015-12-08 09:37:41

1

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

当选中一个单元格时,字体颜色和配件类型会更改,并且选区会淡出。当选中一个选中的单元格时,字体颜色和附件类型会改回,并且选区会淡出。

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

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

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

14

除了上面的很好的答案之外,还有一个快速提示:为了模拟苹果的时钟应用程序的风格(在选中/取消选中行之后使行选择颜色淡出),将其添加到条件后的didSelectRowAtIndexPath

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

从苹果的TableMultiSelect指南。

14
self.tableView.allowsMultipleSelection = YES; 
102

对于多重选择,出列(或初始化)之后加入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 } 
+7

我不明白为什么这不是被接受的答案...如果您使用自定义单元格,还可以更改单元格中的外观setSelected:animated:基于单元格状态的方法 – keisar 2014-04-24 10:01:28

+0

太棒了!奇迹般有效。这个问题的最佳答案。欣赏它! – sermilion 2014-08-03 21:22:43

+3

获取选定的对象索引NSArray * selectedCells = [self.tableView indexPathsForSelectedRows]; – iCoder86 2014-10-20 09:47:08

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

滚动时隐藏选定的行! – Saqib 2014-12-30 05:53:47

1

,因为这是指改变细胞作为你scoll你不能键关机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; 
} 
+0

-1 tableView:didDeselectRowAtIndexPath中的indexPath:不依赖于滚动,并且不需要保留单独的选定项目数组。请参阅@Dmitry解决方案以获得正确的实施 – fishinear 2013-07-24 18:34:46

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