macOS SwiftUI侧边栏应用中如何保留导航状态?
你当前的实现用opacity(0)隐藏未选中的NavigationStack,但SwiftUI会对这类视觉不可见的视图进行优化,导致其内部导航状态被重置。要保留每个详情视图的导航状态,核心是确保未选中的导航栈不会被卸载,仅做视觉隐藏。
具体修改方案
- 替换
ZStack+opacity的方式,改用.hidden()修饰符控制视图显示/隐藏,保证未选中的NavigationStack始终存在于视图层级中 - 保持每个详情视图绑定独立的
NavigationPath变量,实现导航状态的隔离存储
修改后的完整代码
import SwiftUI enum SelectedView { case first, second } enum DetailItem: String, CaseIterable, Hashable { case one, two, three } struct DetailView: View { let label: String var body: some View { VStack { Text(label) ForEach(DetailItem.allCases, id: \.self) { item in NavigationLink(item.rawValue, value: item) } } .navigationTitle(label) } } struct ContentView: View { @State private var selectedItem = SelectedView.first @State private var firstPath = NavigationPath() @State private var secondPath = NavigationPath() var body: some View { NavigationSplitView { List(selection: $selectedItem) { Text("First") .tag(SelectedView.first) Text("Second") .tag(SelectedView.second) } } detail: { Group { NavigationStack(path: $firstPath) { DetailView(label: "First Start") .navigationDestination(for: DetailItem.self) { item in DetailView(label: item.rawValue) } } .hidden(selectedItem != .first) NavigationStack(path: $secondPath) { DetailView(label: "Second Start") .navigationDestination(for: DetailItem.self) { item in DetailView(label: item.rawValue) } } .hidden(selectedItem != .second) } } } }
原理说明
.hidden()仅隐藏视图的视觉表现,不会将其从视图树中移除,因此NavigationStack的导航路径、内部视图状态都会被完整保留- 每个
NavigationStack绑定独立的@State变量NavigationPath,确保不同详情页的导航状态互不干扰 - 避免使用
opacity(0),因为SwiftUI会对低透明度视图进行状态回收优化,导致导航路径被重置
内容的提问来源于stack exchange,提问作者Miles Egan
相关产品推荐
相关产品推荐

