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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 05:57:03