如何从JSON数据创建UITableView层级导航结构?
嘿,我来帮你搞定这个嵌套TableView的导航跳转问题!你的需求其实就是典型的层级化数据展示+导航跳转,咱们一步步来实现,保证清晰易懂:
第一步:修正你的JSON格式
先提个小问题:你给出的示例JSON有语法错误,数组要用[]包裹,字典要用{},修正后的正确格式如下:
[ { "name": "Functions", "icon": "calculator", "subcategories": [ { "name": "Plan Leg", "icon": "globe", "subcategories": [ { "name": "Heading & Groundspeed", "destination": "" }, { "name": "Time & Distance", "destination": "" }, { "name": "Fuel & Distance", "destination": "" } ] } ] } ]
第二步:定义数据模型
为了避免直接用字典操作的繁琐和错误,我们先定义一个符合JSON结构的Category模型,用Codable协议自动解析:
import UIKit struct Category: Codable { let name: String let icon: String? // 部分子项可能没有图标,设为可选类型 let subcategories: [Category]? // 子分类数组,叶子节点为空 let destination: String? // 叶子节点的目标标识,可选 }
第三步:实现通用的TableViewController
我们只需要写一个通用的CategoryTableViewController,不管哪一级分类都可以复用,不用重复写多个控制器:
class CategoryTableViewController: UITableViewController { // 当前层级的分类数据,外部传入 var categories: [Category] = [] override func viewDidLoad() { super.viewDidLoad() // 注册单元格 tableView.register(UITableViewCell.self, forCellReuseIdentifier: "CategoryCell") // 如果是根控制器,默认标题设为"Functions",子控制器会自动替换标题 if navigationController?.viewControllers.first == self { title = "Functions" } } // MARK: - TableView数据源方法 override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return categories.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "CategoryCell", for: indexPath) let currentCategory = categories[indexPath.row] // 设置单元格标题 cell.textLabel?.text = currentCategory.name // 设置图标(这里假设用SF Symbols,你也可以换成自己的本地图片) if let iconName = currentCategory.icon { cell.imageView?.image = UIImage(systemName: iconName) } // 显示跳转箭头:只有存在子分类的单元格才显示箭头 cell.accessoryType = (currentCategory.subcategories != nil && !currentCategory.subcategories!.isEmpty) ? .disclosureIndicator : .none return cell } // MARK: - TableView点击事件 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) let currentCategory = categories[indexPath.row] // 如果有子分类,跳转至新的CategoryTableViewController if let subCategories = currentCategory.subcategories, !subCategories.isEmpty { let subVC = CategoryTableViewController() subVC.categories = subCategories subVC.title = currentCategory.name // 子控制器标题设为当前分类名称 navigationController?.pushViewController(subVC, animated: true) } else { // 叶子节点处理:这里可以根据destination跳转到对应的功能页面 print("点击了功能节点:\(currentCategory.name),目标标识:\(currentCategory.destination ?? "无")") // 示例:if currentCategory.destination == "heading" { push到对应的页面 } } } }
第四步:配置根导航控制器
在你的App启动入口(比如SceneDelegate或者AppDelegate)中,解析JSON并设置根控制器:
// 示例:在SceneDelegate的scene(_:willConnectTo:options:)方法中 func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } let window = UIWindow(windowScene: windowScene) // 解析JSON数据 let sampleJSON = """ [ { "name": "Functions", "icon": "calculator", "subcategories": [ { "name": "Plan Leg", "icon": "globe", "subcategories": [ { "name": "Heading & Groundspeed", "destination": "" }, { "name": "Time & Distance", "destination": "" }, { "name": "Fuel & Distance", "destination": "" } ] } ] } ] """.data(using: .utf8)! do { let categories = try JSONDecoder().decode([Category].self, from: sampleJSON) let rootVC = CategoryTableViewController() rootVC.categories = categories // 包装成导航控制器 let navVC = UINavigationController(rootViewController: rootVC) window.rootViewController = navVC } catch { print("JSON解析失败:\(error)") } window.makeKeyAndVisible() self.window = window }
一些优化建议
- 如果你的图标是本地资源,把
UIImage(systemName: iconName)换成UIImage(named: iconName)即可 - 可以自定义UITableViewCell,让布局更美观(比如调整图标大小、文字间距)
- 叶子节点的
destination可以用来标识不同的功能页面,后续根据这个字段跳转到对应的业务控制器
内容的提问来源于stack exchange,提问作者gilles_yvetot
相关产品推荐
相关产品推荐

