SwiftUI macOS 自定义工具栏状态在侧边栏导航切换后丢失如何解决
问题根因
你当前的toolbar是分别定义在SidebarView和每个ContentView实例中的,侧边栏切换导航时会销毁旧的目标视图、生成新的视图实例,对应挂载的toolbar也会重新初始化,用户自定义的配置自然会被重置。同时不同视图分别定义不同id的toolbar,相当于每次切换都替换了整个工具栏实例,系统无法跨实例保留自定义配置。
解决方案
把全局统一的toolbar定义在不会随导航切换销毁的父视图层级,通过状态变量控制不同导航场景下的按钮显隐,保证整个生命周期内只有一个toolbar实例,自定义配置就可以被系统自动持久化保留。
注意:SwiftUI会自动根据
toolbar(id:)的唯一标识,把用户自定义的工具栏配置持久化到应用的用户偏好设置中,只要保证工具栏id全局唯一、且不会随页面切换被销毁重建,系统就会自动读取和保留用户的自定义修改。
修改后的参考代码如下:
import SwiftUI @main struct TestSidebarApp: App { // 记录当前选中的导航项,用于控制工具栏按钮显隐 @State private var selectedNavItem: Int? = 0 var body: some Scene { WindowGroup { NavigationView { SidebarView(selectedNavItem: $selectedNavItem) // 根据选中的导航项渲染对应内容视图 Group { if selectedNavItem == 0 { ContentView(title: "First Item") } else if selectedNavItem == 1 { ContentView(title: "Second Item") } } } .frame(minWidth: 500, minHeight: 300) // 统一在父视图定义toolbar,唯一id,不会随导航切换销毁 .toolbar(id: "Jpjc8GMi") { // 侧边栏的加号按钮 ToolbarItem(id: "EuRxyg4s", placement: .automatic) { Button(action: {}, label: { Image(systemName: "plus") }) } // 内容页的按钮,根据选中导航项控制是否显示 ToolbarItem(id: "9vTvHYnT", placement: .automatic) { if selectedNavItem != nil { Button(action: {}, label: { Image(systemName: "archivebox") }) } } ToolbarItem(id: "GjzwKktt", placement: .automatic) { if selectedNavItem != nil { Button(action: {}, label: { Image(systemName: "trash") }) } } } } .commands { SidebarCommands() ToolbarCommands() } } } struct ContentView: View { let title: String var body: some View { List { Text("Hello, world!") } .navigationTitle(title) // 移除子视图里的toolbar定义 } } struct SidebarView: View { @Binding var selectedNavItem: Int? var body: some View { List(selection: $selectedNavItem) { Label("First Item", systemImage: "folder") .tag(0) Label("Second Item", systemImage: "folder") .tag(1) } .listStyle(SidebarListStyle()) // 移除侧边栏里的toolbar定义 } }
如果不同导航分区的工具栏差异很大,也可以给不同分区的toolbar设置相同的全局唯一id,保证系统识别为同一个工具栏实例,自定义配置也可以跨切换保留。
内容的提问来源于stack exchange,提问作者Roman Banks
相关产品推荐
相关产品推荐

