如何实现自定义ViewControllerCell的展开收缩:高度翻倍且内容不调整
实现单元格翻倍高度展开且下方单元格下移的方案
1. 维护单元格展开状态(规避复用问题)
UITableViewCell存在复用机制,不能将展开状态存在cell内部,需在ViewController中统一维护每个单元格的状态:
class YourViewController: UIViewController { // 单组列表用数组存储状态,多组可改用[IndexPath: Bool]字典 private var expandedStates: [Bool] = [] override func viewDidLoad() { super.viewDidLoad() // 假设yourDataSource是你的数据源数组,初始化所有单元格为折叠状态 expandedStates = Array(repeating: false, count: yourDataSource.count) tableView.rowHeight = UITableView.automaticDimension tableView.estimatedRowHeight = 100 // 替换为你的cell默认高度 } }
2. 修改选中事件,切换状态并刷新行高
在单元格选中时切换对应位置的展开状态,触发tableView重新计算该行高度:
extension YourViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { // 切换当前单元格的展开状态 expandedStates[indexPath.row] = !expandedStates[indexPath.row] // 刷新该行,让tableView重新计算高度 tableView.reloadRows(at: [indexPath], with: .automatic) tableView.deselectRow(at: indexPath, animated: true) } }
3. 固定单元格内部内容,避免随高度调整
确保ViewControllerCell的子视图约束固定位置与高度,不随cell高度变化拉伸:
class ViewControllerCell: UITableViewCell { private let titleLabel = UILabel() private let contentStackView = UIStackView() override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) setupSubviews() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func setupSubviews() { contentView.addSubview(titleLabel) contentView.addSubview(contentStackView) titleLabel.snp.makeConstraints { make in make.top.left.right.equalToSuperview().inset(16) make.height.equalTo(20) // 固定高度,不随cell变化 } contentStackView.snp.makeConstraints { make in make.top.equalTo(titleLabel.snp.bottom).offset(8) make.left.right.equalToSuperview().inset(16) make.height.equalTo(40) // 固定高度 // 注意:不要设置bottom.equalToSuperview(),新增的cell高度会成为空白区域 } } }
4. 动态返回单元格高度
在数据源代理方法中,根据展开状态返回对应高度:
extension YourViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return yourDataSource.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell(withIdentifier: "ViewControllerCell", for: indexPath) as? ViewControllerCell else { return UITableViewCell() } // 配置cell内容 return cell } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { let defaultHeight: CGFloat = 100 // 替换为你的cell默认高度 return expandedStates[indexPath.row] ? defaultHeight * 2 : defaultHeight } }
核心要点
- 状态维护在数据源层:避免cell复用导致的状态混乱
- 内容固定约束:子视图不绑定cell底部,确保高度增加时内容位置不变
- 刷新行高:通过
reloadRows触发高度重计算,下方单元格会自动下移
内容的提问来源于stack exchange,提问作者Rodrigo
相关产品推荐
相关产品推荐

