如何用最新API替代已废弃的NavigationView实现苹果设备布局?
重构方案:统一适配的SwiftUI布局实现
我之前通过horizontalSizeClass分别实现了iPhone和iPad的布局,使用了已废弃的NavigationView和NavigationLink。现在改用最新SwiftUI API实现相同效果,无需分开编写两种布局,同时支持最多6级深度导航。以下是重构后的完整代码:
1. 统一的主视图(无需区分尺寸类)
直接利用NavigationSplitView和NavigationStack的自动适配能力,不再需要单独处理iPhone/iPad入口:
struct ContentView: View { @State private var selectedTab: AppItem = .welcome @State private var navigationPath = NavigationPath() var body: some View { TabView(selection: $selectedTab) { Welcome() .tabItem { Label("Welcome", systemImage: "square") } .tag(AppItem.welcome) Profile() .tabItem { Label("Profile", systemImage: "triangle") } .tag(AppItem.profile) NavigationSplitView { SidebarView(navigationPath: $navigationPath) } detail: { NavigationStack(path: $navigationPath) { FoobarOverview() .navigationDestination(for: AppItem.self) { item in item.destination } .navigationDestination(for: String.self) { title in Detail(title: title) } } } .tabItem { Label("Overview", systemImage: "circle") } .tag(AppItem.foobar) } } }
2. 优化后的导航项枚举
简化嵌套逻辑,统一数据源,确保所有可导航项支持哈希识别:
indirect enum AppItem: Hashable, Identifiable { var id: Int { hashValue } case foobar, profile, welcome, articles, books, websites @ViewBuilder var destination: some View { switch self { case .foobar: FoobarOverview() case .profile: Profile() case .welcome: Welcome() case .articles: Overview(navTitle: "Articles") case .books: Overview(navTitle: "Books") case .websites: Overview(navTitle: "Websites") } } var name: String { switch self { case .foobar: return "Foobar" case .profile: return "Profile" case .welcome: return "Welcome" case .articles: return "Articles" case .books: return "Books" case .websites: return "Websites" } } static var sidebarItems: [AppItem] = [.welcome, .profile, .foobar] static var foobarSubItems: [AppItem] = [.articles, .books, .websites] }
3. 通用侧边栏视图
自动适配紧凑/常规尺寸类,在iPhone上转为导航栈列表,在iPad上显示为侧边栏:
struct SidebarView: View { @Binding var navigationPath: NavigationPath var body: some View { List { ForEach(AppItem.sidebarItems) { item in NavigationLink(value: item) { Text(item.name) } } Section("Foobar") { ForEach(AppItem.foobarSubItems) { item in NavigationLink(value: item) { Text(item.name) } } } } .listStyle(.sidebar) } }
4. 更新导航视图(适配新API)
将旧版NavigationLink替换为值绑定形式,支持多级路径导航:
struct FoobarOverview: View { var body: some View { List { ForEach(AppItem.foobarSubItems) { item in NavigationLink(value: item) { Text(item.name) } } } .navigationTitle("Foobar") } } struct Overview: View { var navTitle: String var body: some View { List { ForEach(0...10, id: \.self) { num in let detailTitle = "\(navTitle) number: \(num)" NavigationLink(value: detailTitle) { Text(detailTitle) } } } .navigationTitle(navTitle) } }
5. 保留原有基础视图
struct Profile: View { var body: some View { Text("Profile") .navigationTitle("Profile") } } struct Welcome: View { var body: some View { Text("Welcome") .navigationTitle("Welcome") } } struct Detail: View { var title: String var body: some View { Text(title) .navigationTitle(title) } }
核心优化说明
- 自动适配布局:
NavigationSplitView在常规尺寸类(iPad)显示多列布局,紧凑尺寸类(iPhone)自动转为堆叠导航栈,无需手动判断horizontalSizeClass - 多级导航支持:
NavigationPath可存储任意哈希类型的导航节点,轻松支持6级以上深度导航 - 统一数据源:不再区分iPhone/iPad的不同导航数组,通过组件自动适配显示逻辑
- 使用最新API:替换已废弃的
NavigationView和旧版NavigationLink,采用NavigationStack+navigationDestination的现代导航模式
内容的提问来源于stack exchange,提问作者Carsten
相关产品推荐
相关产品推荐

