新手一枚
问题如下:
我想用 TableView 做一个可以多项选择的表格,然后把 tableView的allowsMultipleSelection 属性设为了YES;
_tableView.allowsMultipleSelection = YES;
在 didSelectRowAtIndexPath 和 didDeselectRowAtIndexPath 方法里面使用了如下方法实现了点击单元格然后用check mark 标记的方式。
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
}
但是运行起来发现单元格重用问题会影响到check mark的标记。
具体表现是点击第一个单元格之后,滚动页面,后面重用的单元格也会显示check mark的对号标记,但是单元格是未选中状态。
我怀疑是在 cellForRowAtIndexPath 这个函数上的调用出了问题。
请问有没有解决这个问题的更好的写法?
万分感谢。
附部分相关代码:
//tableVie的创建
_tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, kTopViewHeight, kScreenWidth, kTableViewHeight) style:UITableViewStylePlain];
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.allowsMultipleSelection = YES;
[_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:identifier];
//tableVieCell的创建
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
cell.textLabel.text = _dataArray[indexPath.row];
return cell;
}
首先表扬一下,问题提得很棒~ 格式整齐,代码贴得很全,赞一个。
其次,这个思路不对。
你想要做一个多项选择的表格,最终目的不光是为了给选中的 cell 打勾,更是为了得到用户选择的数据。如果你得不到哪一项选中了、哪一项没选中的数据,就算打勾打正确了有什么用呢?
所以正确的思路就应该是围绕着记录选中/没选中的数据出发。在didSelectRow
、didDeselectRow
里操作数据的变化,然后通过 reloadData 显示出来。
-
设一个
NSMutableArray
属性,元素个数跟你的_dataArray
一样,初始化里面存的都是0
。NSMutableArray* selectionArray = [NSMutableArray array]; for (NSInteger i = 0; i < _dataArray.count; i++) { [selectionArray addObject:@(0)]; // 0 表示未选中,1 表示选中了 } self.selectionArray = selectionArray;
-
在
didSelectRowAtIndexPath:
里:[self.selectionArray replaceObjectAtIndex:indexPath.row withObject:@(1)]; [self.tableView reloadData];
-
在
didDeselectRowAtIndexPath
里:[self.selectionArray replaceObjectAtIndex:indexPath.row withObject:@(0)]; [self.tableView reloadData];
-
在
cellForRow
里:UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; cell.textLabel.text = _dataArray[indexPath.row]; NSInteger selected = [self.selectionArray[indexPath.row] IntegerValue]; if (selected == 0) { cell.accessoryType = UITableViewCellAccessoryNone; } else { cell.accessoryType = UITableViewCellAccessoryCheckmark; } return cell;
楼上说的我解释一下
他说不要用Cell的accessoryType来作为模型,而是应该有单独的数据对象
不过你这个情况不却是也不需要多写个容器纪录选中状态,因为UITableView本来就支持多选纪录
cell 有
accessoryType
属性, 也有selected
属性你想用
accessoryType
属性 表现 被选中这个状态, 但是复用机制存在,产生了bug
所以你有两个解决方案
继承UITableViewCell,在setSeleted:animated:方法里面,根据选择状态,修改accessoryType
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
self.accessoryType = selected?UITableViewCellAccessoryCheckmark:UITableViewCellAccessoryNone;
// Configure the view for the selected state
}
如果懒得继承,那就在- (UITableViewCell )tableView:(UITableView )tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath回调里面,根据cell的selected属性,修改吧,效果一样的,代码同1
祝你好运
MVCMVCMVC
模型模型模型
模型驱动视图模型驱动视图模型驱动视图
面向对象面向对象面向对象
重要事情说三遍