TableView控制器中如何点击DefaultCell调用ExpansionCell?
点击DefaultCell调用ExpansionCell的实现方案
嘿,这个需求在TableView开发里挺常见的,我给你两种实用的实现思路,你可以根据自己的业务场景来选:
方案一:动态修改数据源,插入/删除ExpansionCell
这种方式是通过维护一个包含单元格类型和状态的数据源,点击DefaultCell时切换展开状态,然后在对应的位置插入或移除ExpansionCell,适合ExpansionCell作为独立行的场景。
步骤1:定义数据模型
首先我们需要一个能标记单元格类型和展开状态的模型,用来管理数据源:
// 定义单元格类型 enum CellType { case defaultCell(data: YourDefaultDataModel) // 替换成你实际的DefaultCell数据模型 case expansionCell(data: YourExpansionDataModel) // 替换成你实际的ExpansionCell数据模型 } // 每个列表项的结构,包含类型和展开状态(仅针对DefaultCell) struct CellListItem { var type: CellType var isExpanded: Bool = false }
步骤2:配置TableView数据源
在你的TableViewController里,用上面的模型数组作为数据源,实现基本的数据源方法:
var cellItems: [CellListItem] = [] // 初始化时填充你的DefaultCell数据 override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return cellItems.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let item = cellItems[indexPath.row] switch item.type { case .defaultCell(let data): let cell = tableView.dequeueReusableCell(withIdentifier: "DefaultCell", for: indexPath) as! DefaultCell cell.configure(with: data) // 调用你自己的配置方法填充数据 return cell case .expansionCell(let data): let cell = tableView.dequeueReusableCell(withIdentifier: "ExpansionCell", for: indexPath) as! ExpansionCell cell.configure(with: data) // 同理配置ExpansionCell数据 return cell } }
步骤3:处理点击事件
在didSelectRowAt方法里,判断点击的是DefaultCell,然后切换展开状态,插入或删除ExpansionCell:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) let currentItem = cellItems[indexPath.row] // 只处理DefaultCell的点击 guard case .defaultCell = currentItem.type else { return } // 切换展开状态 var updatedItem = currentItem updatedItem.isExpanded = !updatedItem.isExpanded cellItems[indexPath.row] = updatedItem // 根据状态更新数据源和表格 if updatedItem.isExpanded { // 准备ExpansionCell的数据,替换成你实际的数据源 let expansionData = YourExpansionDataModel(...) let expansionItem = CellListItem(type: .expansionCell(data: expansionData), isExpanded: false) cellItems.insert(expansionItem, at: indexPath.row + 1) // 插入行的动画效果 tableView.insertRows(at: [IndexPath(row: indexPath.row + 1, section: indexPath.section)], with: .automatic) } else { // 删除对应的ExpansionCell cellItems.remove(at: indexPath.row + 1) tableView.deleteRows(at: [IndexPath(row: indexPath.row + 1, section: indexPath.section)], with: .automatic) } }
方案二:将ExpansionCell嵌套进DefaultCell,实现折叠展开
如果你的ExpansionCell不需要作为独立行,而是DefaultCell的展开内容,那可以把它嵌套进DefaultCell里,通过控制单元格高度来实现展开收起。
步骤1:改造DefaultCell
在DefaultCell内部添加ExpansionCell作为子视图,通过约束控制它的显示/隐藏:
class DefaultCell: UITableViewCell { private var expansionHeightConstraint: NSLayoutConstraint! var isExpanded: Bool = false { didSet { // 切换展开状态时,修改高度约束并添加动画 expansionHeightConstraint.constant = isExpanded ? 120 : 0 // 120替换成ExpansionCell的实际高度 UIView.animate(withDuration: 0.3) { self.layoutIfNeeded() } } } override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) setupExpansionCell() } required init?(coder: NSCoder) { super.init(coder: coder) setupExpansionCell() } private func setupExpansionCell() { // 初始化ExpansionCell let expansionCell = ExpansionCell(style: .default, reuseIdentifier: "ExpansionCell") expansionCell.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(expansionCell) // 设置约束:左右对齐,顶部接DefaultCell内容底部,底部接cell底部,高度默认0 expansionHeightConstraint = expansionCell.heightAnchor.constraint(equalToConstant: 0) NSLayoutConstraint.activate([ expansionCell.topAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 8), expansionCell.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16), expansionCell.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16), expansionHeightConstraint, expansionCell.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8) ]) } // 配置DefaultCell的主内容 func configure(with data: YourDefaultDataModel) { // 填充你的DefaultCell数据,比如设置textLabel的文本等 } }
步骤2:处理TableView点击和行高
在TableViewController里,点击DefaultCell时切换它的展开状态,并刷新行高:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) guard let defaultCell = tableView.cellForRow(at: indexPath) as? DefaultCell else { return } defaultCell.isExpanded = !defaultCell.isExpanded // 刷新行高,让TableView重新计算单元格高度 tableView.beginUpdates() tableView.endUpdates() } // 动态计算单元格高度 override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { if let cell = tableView.cellForRow(at: indexPath) as? DefaultCell { let defaultBaseHeight: CGFloat = 60 // DefaultCell未展开时的基础高度 return defaultBaseHeight + (cell.isExpanded ? 136 : 0) // 136是ExpansionCell高度+上下间距 } return UITableView.automaticDimension }
注意事项
- 记得在
viewDidLoad里注册两个单元格的标识符:tableView.register(DefaultCell.self, forCellReuseIdentifier: "DefaultCell"),ExpansionCell同理。 - 代码里的模型类、高度值都要根据你的实际UI和业务逻辑调整。
内容的提问来源于stack exchange,提问作者goga
相关产品推荐
相关产品推荐

