You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iPadOS 18进阶TabBar模式下导航标题自动隐藏问题问询

iPad展开SplitView时TabBarController内导航栏标题/按钮不可见

问题现象

  • 在iOS 18环境下,UITabBarController启用.tabSidebar模式,每个标签页嵌套UISplitViewController时,展开或折叠SplitView后,导航栏的标题及导航栏按钮在UI中不可见,但通过视图层级检查可确认这些元素实际存在。
  • 该问题在直接使用UITabBarController子类,或把它作为子控制器嵌入时均会复现。

复现代码

class TabBarController: UITabBarController,UISplitViewControllerDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()
        let tabTitles = ["First", "Second", "Third", "Fourth", "Fifth", "Sixth"]
        if #available(iOS 18.0, *) {
            mode = .tabSidebar
            var tabs = [UITab]()

            for title in tabTitles {
                let tab = UITab(title: title, image: UIImage(systemName: "leaf"), identifier: title, viewControllerProvider: {_ in
                    return self.createSplitViewController()
                })
                tabs.append(tab)
            }
            setTabs(tabs, animated: true)
        }
    }

    func createSplitViewController() -> UISplitViewController {
        let splitViewController = UISplitViewController()
        splitViewController.preferredDisplayMode = .oneBesideSecondary

        let masterViewController = UINavigationController(rootViewController: MasterViewController())
        let detailViewController = UINavigationController(rootViewController: DetailViewController())
        masterViewController.navigationBar.backgroundColor = .red
        detailViewController.navigationBar.backgroundColor = .blue

        splitViewController.viewControllers = [masterViewController, detailViewController]
        return splitViewController
    }
}

解决方案

方法1:监听SplitView显示模式变化,强制刷新导航栏布局

给UISplitViewController设置代理,在显示模式变更时手动触发导航栏的布局更新,修复布局偏移问题:

// 在TabBarController中实现UISplitViewControllerDelegate的方法
func splitViewController(_ svc: UISplitViewController, willChangeToDisplayMode displayMode: UISplitViewController.DisplayMode) {
    // 遍历SplitView内的所有导航控制器,强制刷新布局
    for nav in svc.viewControllers.compactMap({ $0 as? UINavigationController }) {
        nav.navigationBar.setNeedsLayout()
        nav.navigationBar.layoutIfNeeded()
    }
}

// 同时在createSplitViewController方法中设置代理
func createSplitViewController() -> UISplitViewController {
    let splitViewController = UISplitViewController()
    splitViewController.preferredDisplayMode = .oneBesideSecondary
    splitViewController.delegate = self // 添加这行代码

    let masterViewController = UINavigationController(rootViewController: MasterViewController())
    let detailViewController = UINavigationController(rootViewController: DetailViewController())
    masterViewController.navigationBar.backgroundColor = .red
    detailViewController.navigationBar.backgroundColor = .blue

    splitViewController.viewControllers = [masterViewController, detailViewController]
    return splitViewController
}

方法2:禁用TabBarController的自动滚动视图插入调整

iOS 18的.tabSidebar模式下,系统可能自动调整导航栏的内边距,导致内容被遮挡。可以在TabBarController的viewDidLoad中添加以下代码:

override func viewDidLoad() {
    super.viewDidLoad()
    // ... 原有代码 ...
    if #available(iOS 18.0, *) {
        automaticallyAdjustsScrollViewInsets = false
    }
}

方法3:使用自定义标题视图替代系统标题

如果前两种方法无效,直接自定义导航栏标题视图,绕过系统布局问题:
在MasterViewController和DetailViewController的viewDidLoad中添加:

override func viewDidLoad() {
    super.viewDidLoad()
    // 自定义标题视图
    let titleLabel = UILabel()
    titleLabel.text = "你的页面标题"
    titleLabel.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
    titleLabel.textColor = .label // 适配深色模式
    navigationItem.titleView = titleLabel
    
    // 若有导航栏按钮,也可手动创建并添加
    let rightBarButton = UIBarButtonItem(title: "操作", style: .plain, target: self, action: #selector(handleAction))
    navigationItem.rightBarButtonItem = rightBarButton
}

@objc private func handleAction() {
    // 按钮点击逻辑
}

内容的提问来源于stack exchange,提问作者iroh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 04:47:11