在 iPad 上替代“底部 TabBar 主导航”、实现「侧边栏 + 顶部导航」的多层级高效导航,核心是利用 iOS 原生的 UISplitViewController(拆分视图控制器)结合 UINavigationController,适配大屏交互逻辑的同时兼顾小尺寸/竖屏的折叠场景。以下是具体实现步骤 + 关键代码 + 体验优化,以 Swift 为例:

一、核心思路

iPad 横屏时:左侧展示「侧边栏(菜单)」,右侧展示「顶部导航 + 内容区」,侧边栏可收起/展开;
iPad 竖屏/分屏小尺寸时:侧边栏自动折叠为「顶部导航的下拉菜单」或「全屏时的侧边抽屉」,保持操作一致性;
多层级管理:侧边栏控制一级分类,顶部导航控制二级/三级功能,内容区展示具体页面。

二、具体实现步骤

1. 基础架构搭建(SplitViewController + NavigationController)

UISplitViewController 是 iPad 侧边栏的核心组件,默认分为「主视图(Primary)」和「详情视图(Secondary)」,主视图放侧边栏,详情视图嵌套 UINavigationController 承载顶部导航 + 内容。

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // 1. 创建侧边栏(主视图)
        let sidebarVC = SidebarViewController()
        let sidebarNav = UINavigationController(rootViewController: sidebarVC)

        // 2. 创建详情区(顶部导航 + 初始内容)
        let homeVC = HomeViewController()
        let detailNav = UINavigationController(rootViewController: homeVC)

        // 3. 初始化 SplitViewController
        let splitVC = UISplitViewController(style: .doubleColumn)
        splitVC.preferredStyle = .sidebar // 强制侧边栏样式(iPad 优先)
        splitVC.setViewController(sidebarNav, for: .primary)
        splitVC.setViewController(detailNav, for: .secondary)

        // 4. 配置 SplitView 行为
        splitVC.preferredSplitBehavior = .tile // 横屏时侧边栏固定,不自动隐藏
        splitVC.presentsWithGesture = true // 支持滑动呼出/收起侧边栏
        splitVC.delegate = self // 监听折叠/展开状态

        // 5. 设置根视图
        window = UIWindow(frame: UIScreen.main.bounds)
        window?.rootViewController = splitVC
        window?.makeKeyAndVisible()

        return true
    }
}

// MARK: - SplitViewController 代理(处理折叠/展开)
extension AppDelegate: UISplitViewControllerDelegate {
    func splitViewController(_ svc: UISplitViewController, topColumnForCollapsingToProposedTopColumn proposedTopColumn: UISplitViewController.Column) -> UISplitViewController.Column {
        // 折叠时优先保留详情区(顶部导航)
        return .secondary
    }
}

2. 实现侧边栏(SidebarViewController)

侧边栏用 UITableView 实现一级菜单,选中项时触发详情区的页面跳转,适配 iPad 触控尺寸(行高、间距放大)。

class SidebarViewController: UITableViewController {
    // 一级菜单数据
    let menuItems = [
        ("首页", UIImage(systemName: "house")),
        ("文档", UIImage(systemName: "doc.text")),
        ("设置", UIImage(systemName: "gear")),
        ("关于", UIImage(systemName: "info.circle"))
    ]

    override func viewDidLoad() {
        super.viewDidLoad()
        // 适配 iPad 样式
        tableView.rowHeight = 60 // 行高比手机端大(手机端通常44-50pt)
        tableView.separatorInset = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)
        tableView.backgroundColor = .systemBackground

        // 隐藏侧边栏自身的导航栏(仅保留详情区顶部导航)
        navigationController?.setNavigationBarHidden(true, animated: false)
    }

    // MARK: - TableView 代理
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return menuItems.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: .default, reuseIdentifier: "SidebarCell")
        let (title, icon) = menuItems[indexPath.row]
        cell.textLabel?.text = title
        cell.textLabel?.font = UIFont.systemFont(ofSize: 16, weight: .medium) // 字号放大
        cell.imageView?.image = icon
        cell.imageView?.tintColor = .systemBlue
        cell.accessoryType = .disclosureIndicator // 指示可跳转
        // 最小点击区域确保 44pt×44pt(iPad 触控更友好)
        cell.contentView.layoutMargins = UIEdgeInsets(top: 10, left: 16, bottom: 10, right: 16)
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)

        // 获取 SplitView 的详情区导航控制器
        guard let splitVC = self.splitViewController,
              let detailNav = splitVC.viewController(for: .secondary) as? UINavigationController else {
            return
        }

        // 根据选中项跳转对应页面(二级内容)
        switch indexPath.row {
        case 0:
            detailNav.setViewControllers([HomeViewController()], animated: true)
        case 1:
            detailNav.setViewControllers([DocumentViewController()], animated: true)
        case 2:
            detailNav.setViewControllers([SettingViewController()], animated: true)
        case 3:
            detailNav.setViewControllers([AboutViewController()], animated: true)
        default:
            break
        }
    }
}

3. 详情区顶部导航(UINavigationController)

详情区的每个页面嵌套在 UINavigationController 中,实现二级/三级导航,同时适配 iPad 顶部导航的样式:

class HomeViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white

        // 1. 配置顶部导航栏(iPad 样式)
        navigationItem.title = "首页"
        navigationController?.navigationBar.prefersLargeTitles = true // 大标题(iPad 更醒目)
        navigationItem.largeTitleDisplayMode = .always

        // 2. 添加二级操作按钮(顶部导航右侧)
        let addBtn = UIBarButtonItem(
            barButtonSystemItem: .add,
            target: self,
            action: #selector(addAction)
        )
        let filterBtn = UIBarButtonItem(
            image: UIImage(systemName: "slider.horizontal.3"),
            style: .plain,
            target: self,
            action: #selector(filterAction)
        )
        navigationItem.rightBarButtonItems = [addBtn, filterBtn]

        // 3. 适配 iPad 内容区布局(示例:添加一个列表)
        let listView = UITableView(frame: view.bounds)
        listView.rowHeight = 60
        listView.dataSource = self
        view.addSubview(listView)
        listView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            listView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            listView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            listView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            listView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
        ])
    }

    @objc func addAction() {
        // 跳转到三级页面(示例:新建文档)
        let createVC = CreateDocumentViewController()
        navigationController?.pushViewController(createVC, animated: true)
    }

    @objc func filterAction() {
        // 顶部导航的二级操作(示例:筛选)
        let filterVC = FilterViewController()
        filterVC.modalPresentationStyle = .popover // iPad 弹出式弹窗(不占满屏)
        filterVC.popoverPresentationController?.barButtonItem = navigationItem.rightBarButtonItems?[1]
        present(filterVC, animated: true)
    }
}

// MARK: - 内容区列表适配
extension HomeViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 20
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "HomeCell")
        cell.textLabel?.text = "内容项 \(indexPath.row + 1)"
        cell.detailTextLabel?.text = "iPad 适配的详情描述"
        cell.detailTextLabel?.font = UIFont.systemFont(ofSize: 14)
        return cell
    }
}

4. 适配折叠/分屏场景(关键优化)

当 iPad 竖屏、分屏小尺寸时,侧边栏会自动折叠,需在详情区顶部导航添加「侧边栏呼出按钮」,保证操作入口不丢失:

// 在详情区的基类 ViewController 中统一处理
class BaseDetailViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // 添加侧边栏呼出按钮(仅折叠时显示)
        let sidebarBtn = UIBarButtonItem(
            image: UIImage(systemName: "sidebar.left"),
            style: .plain,
            target: self,
            action: #selector(toggleSidebar)
        )
        navigationItem.leftBarButtonItem = sidebarBtn
    }

    @objc func toggleSidebar() {
        // 触发 SplitView 展开/收起侧边栏
        splitViewController?.show(.primary)
    }

    // 监听 SplitView 折叠状态,动态显示/隐藏呼出按钮
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        guard let splitVC = splitViewController else { return }
        // 折叠状态(竖屏/小尺寸)显示呼出按钮,展开状态隐藏
        navigationItem.leftBarButtonItem?.isHidden = !splitVC.isCollapsed
    }
}

// 让所有详情页面继承 BaseDetailViewController
class HomeViewController: BaseDetailViewController { /* ... */ }
class DocumentViewController: BaseDetailViewController { /* ... */ }

三、体验优化要点(iPad 专属)

  1. 控件尺寸适配

    • 侧边栏行高 ≥ 60pt,顶部导航按钮点击区域 ≥ 44pt×44pt;
    • 内容区文本字号比手机端大 2-4pt(如正文 16pt,副标题 14pt);
    • 弹窗优先使用 UIPopoverPresentationController(iPad 弹出式),而非占满屏的 modal
  2. 横竖屏切换适配

    • 重写 viewWillTransition(to:with:) 监听屏幕旋转,调整 SplitView 布局:
      override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
       super.viewWillTransition(to: size, with: coordinator)
       coordinator.animate { _ in
           self.tableView.reloadData() // 刷新内容区布局
           self.navigationItem.leftBarButtonItem?.isHidden = !self.splitViewController?.isCollapsed ?? false
       }
      }
  3. 台前调度(Stage Manager)适配

    • 支持多窗口:在 Info.plist 中开启 Application Scene ManifestEnable Multiple Windows = YES;
    • 确保每个窗口的 SplitView 独立工作,不共享状态。
  4. 键盘/指针交互适配

    • 顶部导航支持硬件键盘快捷键(如 Cmd+1 跳转到首页):
      override var keyCommands: [UIKeyCommand]? {
       return [
           UIKeyCommand(input: "1", modifierFlags: .command, action: #selector(jumpToHome)),
           UIKeyCommand(input: "2", modifierFlags: .command, action: #selector(jumpToDocument))
       ]
      }
    • 为侧边栏/顶部导航按钮添加指针悬停效果:
      let pointerInteraction = UIPointerInteraction(delegate: self)
      addBtn.addInteraction(pointerInteraction)

四、替代方案(非原生)

如果需要更自定义的侧边栏(如可拖拽宽度、自定义样式),可使用第三方库:

  • SideMenu:轻量级自定义侧边栏,支持 iPad 分屏适配;
  • SwiftUI 方案:用 NavigationSplitView 替代 UISplitViewController,代码更简洁(iOS 16+ 支持):
    struct ContentView: View {
      var body: some View {
          NavigationSplitView {
              // 侧边栏
              List(menuItems) { item in
                  NavigationLink(item.title, destination: DetailView(item: item))
              }
              .listRowHeight(60)
          } detail: {
              // 详情区(顶部导航 + 内容)
              NavigationStack {
                  HomeView()
                      .navigationTitle("首页")
                      .navigationBarTitleDisplayMode(.large)
              }
          }
      }
    }

总结

核心是通过 UISplitViewController(或 SwiftUI 的 NavigationSplitView)实现「侧边栏(一级)+ 顶部导航(二级/三级)」的结构,兼顾 iPad 大屏的空间优势和分屏/竖屏的折叠场景。关键是适配不同尺寸下的导航入口不丢失控件尺寸符合 iPad 触控习惯交互逻辑贴近桌面端效率