如何实现点击UITableView某行时自动关闭其他已展开行
解决UITableView仅允许单个可展开单元格展开的问题
需求是实现UITableView中同一时间仅能有一个可展开单元格处于展开状态,当前代码仅能切换点击行的展开状态,但无法自动关闭其他已展开的行,必须手动点击对应行才能关闭。
修改后的视图控制器代理代码
extension HelpVC: UITableViewDelegate, UITableViewDataSource { func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { UITableView.automaticDimension } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { // 先关闭所有已展开的单元格 let previouslyExpandedIndex = dataSource.firstIndex { $0.isExpanded } if let expandedIndex = previouslyExpandedIndex { dataSource[expandedIndex].isExpanded = false } // 切换当前点击行的展开状态 dataSource[indexPath.row].isExpanded.toggle() // 刷新整个表格,确保所有单元格状态更新 questionsTableView.reloadData() } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell(withIdentifier: ExpandableTableViewCell.reuseIdentifier, for: indexPath) as? ExpandableTableViewCell else { return UITableViewCell() } cell.set(dataSource[indexPath.row]) return cell } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { dataSource.count } }
关键修改说明
- 在点击行时,先遍历数据源找到之前处于展开状态的单元格,将其
isExpanded设为false,确保其他行都被关闭 - 再切换当前点击行的
isExpanded状态 - 使用
questionsTableView.reloadData()替代原来的reloadRows,一次性更新所有单元格的状态,避免只刷新单个行导致其他已展开行状态不更新的问题
如果担心reloadData的性能问题,也可以只刷新受影响的行,更适合数据量较大的场景:
// 替换reloadData的部分 var reloadIndexPaths = [indexPath] if let expandedIndex = previouslyExpandedIndex { reloadIndexPaths.append(IndexPath(row: expandedIndex, section: 0)) } questionsTableView.reloadRows(at: reloadIndexPaths, with: .automatic)
内容的提问来源于stack exchange,提问作者JOHNY
相关产品推荐
相关产品推荐

