如何提取Hierarchies嵌套结构全层级数据实现UITableView手风琴效果
解决方案
1. 修复模型定义错误
你的AssignedHierarchyLevelModel重复定义了两次Hierarchies结构体,首先删除多余的第二个Hierarchies定义即可,保留的递归结构体本身已经支持任意层级的树形结构,修复后的模型如下:
struct AssignedHierarchyLevelModel { let result: [Result]? init(_ json: JSON) { result = json["result"].arrayValue.map { Result($0) } } struct Result { let name: String? let hierarchies: [Hierarchies]? init(_ json: JSON) { name = json["name"].stringValue hierarchies = json["hierarchies"].arrayValue.map { Hierarchies($0) } } } struct Hierarchies { // 新增唯一ID,用于后续手风琴展开状态标识 let id = UUID() let hierarchyOrder: Int? let hierarchyLevel: Int? let name: String? let hierarchies: [Hierarchies]? let isEnabled: Bool? init(_ json: JSON) { hierarchyOrder = json["hierarchy_order"].intValue hierarchyLevel = json["hierarchy_level"].intValue name = json["name"].stringValue hierarchies = json["hierarchies"].arrayValue.map { Hierarchies($0) } isEnabled = json["is_enabled"].boolValue } } }
2. 实现递归提取全层级节点方法
你之前的numberOfChild方法是硬编码仅处理2级层级,所以无法获取深层数据,替换为递归遍历逻辑即可支持无限层级提取,扩展Hierarchies结构体添加递归方法:
extension AssignedHierarchyLevelModel.Result.Hierarchies { /// 递归获取当前节点的所有层级后代节点,参数控制是否包含节点自身 func allDescendants(includeSelf: Bool = true) -> [AssignedHierarchyLevelModel.Result.Hierarchies] { var result = includeSelf ? [self] : [] hierarchies?.forEach { child in result.append(contentsOf: child.allDescendants()) } return result } }
如果要提取某个Result下的所有层级节点,直接调用即可:
let allNodes = result.hierarchies?.flatMap { $0.allDescendants() } ?? []
3. 业务场景适配
场景1:直接展示所有层级节点(无折叠)
数据绑定时直接拉平所有节点作为数据源即可:
// 存储拉平后的全量节点 var allFlattenNodes: [AssignedHierarchyLevelModel.Result.Hierarchies] = [] func dataBindAccountSettingHierarchyLevel(){ allFlattenNodes.removeAll() self.assignedhierarchyResult = self.assignedHierarchyLevelModel?.result ?? [] // 递归拉平所有层级节点 assignedhierarchyResult.forEach { result in allFlattenNodes.append(contentsOf: result.hierarchies?.flatMap { $0.allDescendants() } ?? []) } tableView.reloadData() } // TableView数据源直接返回数组长度 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return allFlattenNodes.count }
渲染行时根据hierarchyLevel设置左侧缩进即可体现层级关系。
场景2:实现手风琴折叠效果
新增展开状态存储,动态计算当前需要展示的行数:
// 存储当前展开的节点ID var expandedNodeIds = Set<UUID>() // 计算对应Section下需要展示的行数 func getRowCountForSection(_ section: Int) -> Int { guard let topHierarchies = assignedhierarchyResult[section].hierarchies else { return 0 } var count = 0 func countExpandedNodes(nodes: [AssignedHierarchyLevelModel.Result.Hierarchies]) { nodes.forEach { node in count += 1 // 节点已展开则继续统计子节点 if expandedNodeIds.contains(node.id), let children = node.hierarchies, !children.isEmpty { countExpandedNodes(nodes: children) } } } countExpandedNodes(nodes: topHierarchies) return count } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return getRowCountForSection(section) } // 点击节点时切换展开状态 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { // 此处省略获取当前点击节点的逻辑 let currentNode = getNodeForIndexPath(indexPath) guard !currentNode.hierarchies.isEmpty else { return } if expandedNodeIds.contains(currentNode.id) { expandedNodeIds.remove(currentNode.id) } else { expandedNodeIds.insert(currentNode.id) } // 局部刷新对应区域 tableView.reloadSections(IndexSet(integer: indexPath.section), with: .automatic) }
内容的提问来源于stack exchange,提问作者kiran
相关产品推荐
相关产品推荐

