在 iPadOS 18 中恢复底部标签栏
问题描述
iPadOS 18 引入了全新的 UITabBarController
设计样式,默认使用侧边栏风格的悬浮标签栏(如图所示)。
许多开发者希望恢复 iOS 17 及之前版本的底部标签栏设计,主要因为:
- 用户习惯原有底部导航布局
- 新样式与现有界面设计不协调
- 部分应用功能依赖底部标签栏实现
兼容性说明
以下解决方案针对 iPadOS 18+ 设备生效,iOS 17 及以下系统不需要进行特殊处理
推荐解决方案
方法一:覆盖水平尺寸类(推荐)
SwiftUI 实现
swift
TabView {
Tab("功能1", systemImage: "star") {
ContentView1()
.environment(\.horizontalSizeClass, originalSizeClass) // 恢复原始尺寸类
}
Tab("功能2", systemImage: "heart") {
ContentView2()
.environment(\.horizontalSizeClass, originalSizeClass)
}
}
.environment(\.horizontalSizeClass, .compact) // 👈 关键修改
UIKit 实现
swift
class CustomTabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
// 核心设置
if #available(iOS 18.0, *) {
traitOverrides.horizontalSizeClass = .compact // 👈 恢复底部标签栏
}
}
}
处理超过 5 个标签
如果需要显示超过 5 个标签项,使用 .unspecified
替代 .compact
:
swift
traitOverrides.horizontalSizeClass = .unspecified
解决子视图副作用
覆盖尺寸类会影响全部子视图控制器,需单独处理每个子控制器:
swift
class ChildViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 18.0, *) {
// 从窗口获取原始尺寸类
if let windowSize = view.window?.traitCollection.horizontalSizeClass {
traitOverrides.horizontalSizeClass = windowSize
}
}
}
}
屏幕旋转处理
添加以下代码避免旋转后布局异常:
swift
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
if #available(iOS 18.0, *) {
traitOverrides.horizontalSizeClass = .regular
traitOverrides.horizontalSizeClass = .compact
}
}
macOS 特殊场景处理
对于在 macOS (Apple Silicon) 上运行的 iPad 应用:
swift
class MacCompatibleTabController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 18, *), ProcessInfo.processInfo.isiOSAppOnMac {
mode = .tabSidebar
sidebar?.isHidden = true // 隐藏顶部标签栏
traitOverrides.horizontalSizeClass = .compact // 启用底部标签栏
}
}
}
替代方案(不推荐)
通过 UserDefaults 禁用新样式
swift
@main
struct MyApp: App {
init() {
UserDefaults(suiteName: "com.apple.UIKit")?.set(false, forKey: "UseFloatingTabBar")
}
}
不推荐原因
- 使用私有 API 可能导致 App Store 审核拒绝
- 需在 UI 初始化前设置
- 系统升级可能导致失效
兼容未来系统
在 Info.plist
中添加兼容性标志:
xml
<key>UIDesignRequiresCompatibility</key>
<false/>
最佳实践总结
- 首选方案:使用
traitOverrides.horizontalSizeClass = .compact
- 所有子控制器:必须恢复原始尺寸类
- macOS 应用:需额外设置
mode
和isHidden
- 避免方法:UserDefaults 和私有 API 可能带来长期维护问题
- 持续关注:苹果可能在未来版本提供官方 API
长期建议
苹果在 iPadOS 18+ 中推广新设计模式,长期维护应优先考虑适配新设计,而非恢复旧样式