如何保存segmentedController内共用tableView的选中行状态
解决方案
你现有代码已经单独存储了两个分段的选中行位置,只需补充分段切换时的状态同步逻辑即可实现状态保留,具体修改如下:
基础实现(每个分段单选,切换保留选中状态)
步骤1:完善cellForRow的选中状态配置
在cellForRowAt方法中,根据当前选中的分段,判断当前行是否为对应分段的选中行,主动设置cell的选中样式:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "CommonCell", for: indexPath) if segmentedControl.selectedSegmentIndex == 0 { cell.textLabel?.text = viewModel.genres[indexPath.row] // 匹配分类分段的选中状态 cell.accessoryType = viewModel.selectedGenr == indexPath.row ? .checkmark : .none } else { cell.textLabel?.text = viewModel.years[indexPath.row] // 匹配年份分段的选中状态 cell.accessoryType = viewModel.selectedYear == indexPath.row ? .checkmark : .none } return cell }
步骤2:添加分段切换监听
切换分段时重新加载tableView,触发上面的cell配置逻辑,同步对应分段的选中状态:
// 视图加载时给分段控件添加切换监听 segmentedControl.addTarget(self, action: #selector(segmentDidChange(_:)), for: .valueChanged) // 切换触发方法 @objc func segmentDidChange(_ sender: UISegmentedControl) { tableView.reloadData() }
你原有的didSelectRowAt逻辑无需修改,已经满足单选场景下的选中值存储需求。
性能优化方案(避免全量刷新)
如果不想触发全列表刷新,可以在切换分段时手动更新选中行状态,性能更优:
@objc func segmentDidChange(_ sender: UISegmentedControl) { if sender.selectedSegmentIndex == 0 { // 切换到分类分段:清除年份分段的选中高亮,设置分类分段的选中高亮 if let preSelectedYear = viewModel.selectedYear { tableView.deselectRow(at: IndexPath(row: preSelectedYear, section: 0), animated: false) } if let currentSelectedGenr = viewModel.selectedGenr { tableView.selectRow(at: IndexPath(row: currentSelectedGenr, section: 0), animated: false, scrollPosition: .none) } } else { // 切换到年份分段:清除分类分段的选中高亮,设置年份分段的选中高亮 if let preSelectedGenr = viewModel.selectedGenr { tableView.deselectRow(at: IndexPath(row: preSelectedGenr, section: 0), animated: false) } if let currentSelectedYear = viewModel.selectedYear { tableView.selectRow(at: IndexPath(row: currentSelectedYear, section: 0), animated: false, scrollPosition: .none) } } }
扩展实现(每个分段支持多选,保留所有选中行)
如果需要每个分段可选中多行,只需修改ViewModel的存储结构即可:
- 把原有的单个可选Int改为Set存储选中行索引
// ViewModel修改 var selectedGenres: Set<Int> = [] var selectedYears: Set<Int> = []
- 修改
didSelectRowAt逻辑
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { if segmentedControl.selectedSegmentIndex == 0 { if viewModel.selectedGenres.contains(indexPath.row) { viewModel.selectedGenres.remove(indexPath.row) } else { viewModel.selectedGenres.insert(indexPath.row) } } else { if viewModel.selectedYears.contains(indexPath.row) { viewModel.selectedYears.remove(indexPath.row) } else { viewModel.selectedYears.insert(indexPath.row) } } tableView.reloadRows(at: [indexPath], with: .automatic) }
- 修改
cellForRowAt的状态判断逻辑
// 分类分段判断 cell.accessoryType = viewModel.selectedGenres.contains(indexPath.row) ? .checkmark : .none // 年份分段判断 cell.accessoryType = viewModel.selectedYears.contains(indexPath.row) ? .checkmark : .none
内容的提问来源于stack exchange,提问作者Abrcd18
相关产品推荐
相关产品推荐

