UITableView嵌套于UITableViewCell内,内嵌二级TableView仅显示1行无法正常加载

多级嵌套UITableView子节点不展示问题排查与修正方案
问题根因
你遇到的内嵌表固定只显示1行、点击展开不加载子节点的问题,全是UITableView嵌套实现里的高频踩坑,和主表一级分区的实现逻辑没有本质差异,本质是几个关键链路的疏漏:
- 父容器高度裁剪:内嵌UITableView本质是UIScrollView,如果承载它的自定义主cell没有给内嵌表匹配足够的显示高度,哪怕数据源正确返回了4个子节点,超出cell bounds的内容会被直接裁剪,视觉上就只剩1行可见
- 数据源更新未触发表格刷新:主表cell复用时,向内嵌cell传递新的greenDataArray后,没有主动触发内嵌表的重载,表格始终复用初始化时的空/旧数据源状态,自然不会加载新的子节点
- 展开状态未同步:点击section头修改展开折叠状态后,没有把状态变更同步到内嵌表的数据源计算逻辑,也没有触发对应分区的局部刷新,行数计算始终停留在初始的1行状态
- 系统估算偏差:iOS11之后UITableView默认开启行/区头估算高度,嵌套场景下如果没有关闭估算逻辑,会导致contentSize计算偏差,反过来让父cell的自适应高度只算出来1行的高度
具体修正步骤
- 修正内嵌表与父cell的高度逻辑
- 首先关闭内嵌表的估算开关,避免系统估算带来的高度计算误差:
// 关闭默认估算逻辑 embeddedTable.estimatedRowHeight = 0; embeddedTable.estimatedSectionHeaderHeight = 0; embeddedTable.estimatedSectionFooterHeight = 0; - 不要给内嵌表设置硬编码的固定高度,通过KVO监听内嵌表的
contentSize变化动态调整高度约束:在内嵌表数据加载完成后,拿到实际的contentSize.height,更新内嵌表的高度约束,再将整体高度变化回调给主表,触发表格的自适应高度重算,从根源上解决内容被裁剪的问题。
- 首先关闭内嵌表的估算开关,避免系统估算带来的高度计算误差:
- 修正数据源传递的刷新链路
- 自定义嵌套cell的greenDataArray属性,要在属性的赋值监听中完成两件事:同步赋值给内嵌表的数据源引用,立刻调用
embeddedTable reloadData,不要依赖外部手动触发刷新,从流程上避免“数据更新了表没刷新”的问题:- (void)setGreenDataArray:(NSMutableArray *)greenDataArray { _greenDataArray = greenDataArray; // 数据变更后立刻重载内嵌表 [self.embeddedTable reloadData]; // 重载完成后根据新的内容高度更新内嵌表约束 CGFloat realHeight = self.embeddedTable.contentSize.height; self.embeddedTableHeightConstraint.constant = realHeight; [self layoutIfNeeded]; }
- 自定义嵌套cell的greenDataArray属性,要在属性的赋值监听中完成两件事:同步赋值给内嵌表的数据源引用,立刻调用
- 对齐展开交互的刷新逻辑
- 点击内嵌表section头的展开按钮时,先修改对应greenData模型的
isExpanded状态,再触发表格的局部刷新,避免全表刷新的性能损耗:// section头点击响应 - (void)sectionHeaderDidClick:(NSInteger)section { GreenDataModel *model = self.greenDataArray[section]; model.isExpanded = !model.isExpanded; // 局部刷新对应分区 [self.embeddedTable reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationFade]; } - 校验内嵌表的
numberOfRowsInSection实现:必须基于当前section的模型展开状态计算行数,展开时返回子节点数组的实际count,折叠时返回0,不要硬编码返回值。
- 点击内嵌表section头的展开按钮时,先修改对应greenData模型的
- 解决cell复用的状态残留
- 主表的cell复用显示新数据时,要在内嵌cell的
prepareForReuse方法里先清空旧数据源、重置所有section的展开状态,避免上一个cell的展示状态残留到新的复用cell上。
- 主表的cell复用显示新数据时,要在内嵌cell的
内容的提问来源于stack exchange,提问作者Axel
相关产品推荐
相关产品推荐

