ios - 怎么解决用Cell的accessoryType属性标记单元格之后,出现的重用问题,急求大神!

 卖火柴的萌小猪_966 发布于 2022-10-29 20:13

新手一枚

问题如下:

我想用 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;
}
3 个回答
  • MVCMVCMVC
    模型模型模型
    模型驱动视图模型驱动视图模型驱动视图
    面向对象面向对象面向对象

    重要事情说三遍

    2022-10-31 18:44 回答
  • 楼上说的我解释一下

    他说不要用Cell的accessoryType来作为模型,而是应该有单独的数据对象

    不过你这个情况不却是也不需要多写个容器纪录选中状态,因为UITableView本来就支持多选纪录

    1. cell 有 accessoryType 属性, 也有 selected 属性

    2. 你想用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

    祝你好运

    2022-10-31 18:45 回答
  • 首先表扬一下,问题提得很棒~ 格式整齐,代码贴得很全,赞一个。

    其次,这个思路不对。

    你想要做一个多项选择的表格,最终目的不光是为了给选中的 cell 打勾,更是为了得到用户选择的数据。如果你得不到哪一项选中了、哪一项没选中的数据,就算打勾打正确了有什么用呢?

    所以正确的思路就应该是围绕着记录选中/没选中的数据出发。在didSelectRowdidDeselectRow里操作数据的变化,然后通过 reloadData 显示出来。

    1. 设一个NSMutableArray属性,元素个数跟你的_dataArray一样,初始化里面存的都是0

      NSMutableArray* selectionArray = [NSMutableArray array];
      for (NSInteger i = 0; i < _dataArray.count; i++) {
          [selectionArray addObject:@(0)]; // 0 表示未选中,1 表示选中了
      }
      self.selectionArray = selectionArray;
    2. didSelectRowAtIndexPath:里:

      [self.selectionArray replaceObjectAtIndex:indexPath.row withObject:@(1)];
      [self.tableView reloadData];
    3. didDeselectRowAtIndexPath里:

      [self.selectionArray replaceObjectAtIndex:indexPath.row withObject:@(0)];
      [self.tableView reloadData];
    4. 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;
    2022-10-31 18:47 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有