如何在Objective-C中实现最多n级的可展开折叠多级UITableView
通用多级可展开折叠UITableView实现方案(Objective-C)
1. 核心通用节点模型设计
首先需要定义通用节点模型,兼容任意嵌套深度的数组/字典结构,运行时动态生成层级:
- 新建
NodeModel节点类,核心属性如下:nodeId:节点唯一标识,用于快速定位节点parentId:父节点唯一标识,根节点可设为nillevel:当前节点层级,根节点默认值为0,每向下嵌套一级自动+1isExpanded:布尔值,标记当前节点是否处于展开状态subNodes:数组类型,存储当前节点的所有子节点模型rawData:id类型,存储当前节点对应的原始字典/数组数据,供业务层自定义渲染使用
- 新增递归解析方法,将任意嵌套的原始数据转换为节点树结构:
// NodeModel.h 头文件定义 @interface NodeModel : NSObject @property (nonatomic, copy) NSString *nodeId; @property (nonatomic, copy) NSString *parentId; @property (nonatomic, assign) NSInteger level; @property (nonatomic, assign) BOOL isExpanded; @property (nonatomic, strong) NSArray <NodeModel *>*subNodes; @property (nonatomic, strong) id rawData; /// 递归解析嵌套数据生成节点树 /// @param nestedData 原始嵌套数组/字典 /// @param parentId 父节点ID,根节点传nil /// @param level 当前层级,根节点传0 + (NSArray <NodeModel *>*)parseNestedData:(id)nestedData parentId:(NSString *)parentId currentLevel:(NSInteger)level; @end
解析方法实现时只需判断当前传入的原始数据类型是数组还是字典,递归生成子节点即可,无需提前限制层级上限。
2. UITableView数据源处理
控制器内维护两个数组即可实现动态展示:
originalNodeTree:存储完整的节点树结构,数据结构始终不变displayNodes:一维数组,仅存储当前需要展示的节点,和UITableView的行一一对应,只包含已展开的节点链- 节点展开/折叠时只需更新
displayNodes数组,无需修改原始节点树
3. 展开折叠交互实现
点击cell时通过局部刷新实现动画效果,无需 reload 整个列表:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NodeModel *currentNode = self.displayNodes[indexPath.row]; // 无下级节点直接返回,不处理交互 if (currentNode.subNodes.count == 0) return; currentNode.isExpanded = !currentNode.isExpanded; NSMutableArray *updateIndexPaths = [NSMutableArray array]; NSInteger currentPosition = indexPath.row; if (currentNode.isExpanded) { // 展开状态:递归获取当前节点下所有需要展示的子节点,插入到displayNodes NSArray *addSubNodes = [self getAllVisibleSubNodesOfNode:currentNode]; [self.displayNodes insertObjects:addSubNodes atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(currentPosition + 1, addSubNodes.count)]]; // 生成插入对应的indexPath for (NSInteger i = 0; i < addSubNodes.count; i++) { [updateIndexPaths addObject:[NSIndexPath indexPathForRow:currentPosition + 1 + i inSection:0]]; } [tableView insertRowsAtIndexPaths:updateIndexPaths withRowAnimation:UITableViewRowAnimationAutomatic]; } else { // 折叠状态:计算当前节点下所有需要移除的子节点数量,从displayNodes删除 NSInteger removeCount = [self countOfAllSubNodesUnderNode:currentNode]; [self.displayNodes removeObjectsInRange:NSMakeRange(currentPosition + 1, removeCount)]; // 生成删除对应的indexPath for (NSInteger i = 0; i < removeCount; i++) { [updateIndexPaths addObject:[NSIndexPath indexPathForRow:currentPosition + 1 + i inSection:0]]; } [tableView deleteRowsAtIndexPaths:updateIndexPaths withRowAnimation:UITableViewRowAnimationAutomatic]; } }
4. Cell动态适配
- 自定义
NestedTableViewCell,根据节点的level属性动态计算左侧缩进距离,实现层级视觉区分 - 根据节点的
isExpanded状态切换展开/折叠箭头图标 - 通过节点的
rawData属性渲染业务需要的文本、图片等自定义内容
注意事项
- 节点唯一ID需要确保全局唯一,避免递归查找节点时出错,可增加最大嵌套深度限制避免异常的无限嵌套导致死循环
- 数据量较大(千条以上)时可将
displayNodes的更新逻辑放到子线程处理,避免阻塞主线程 - 如需支持多section展示,只需在节点模型中增加section标识字段即可扩展,核心逻辑无需修改
内容的提问来源于stack exchange,提问作者Sumit_VE
相关产品推荐
相关产品推荐

