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

SwiftUI Mac端ToolbarItem在NavigationView分栏间异常跳转问题

解决SwiftUI Mac应用双侧边栏ToolbarItem异常跳转问题

问题根源

你当前的实现是通过切换不同的NavigationView实例来适配侧边栏状态(NoSidebars/LeftSidebars等),每次状态变化都会重建整个导航视图及附属的工具栏。这种方式会让SwiftUI无法正确跟踪ToolbarItem的归属,加上每个子视图单独设置toolbar,最终导致按钮跳转异常。

正确解决方案:使用原生NavigationSplitView

SwiftUI 3.0+提供的NavigationSplitView专门用于多栏布局(完美匹配Xcode的双侧边栏模式),无需切换整个视图,仅通过状态控制栏的显示/隐藏,从根源避免Toolbar异常。

步骤1:调整状态管理

更新你的MenuBarViewModel,直接使用NavigationSplitViewVisibility来控制栏状态:

import SwiftUI

class MenuBarViewModel: ObservableObject {
    static let shared = MenuBarViewModel()
    // 初始显示所有侧边栏
    @Published var columnVisibility: NavigationSplitViewVisibility = .all
}

步骤2:重构ContentView为单NavigationSplitView

移除所有分栏视图(NoSidebars/LeftSidebars等),用单个NavigationSplitView实现布局,并统一设置工具栏:

struct ContentView: View {
    @ObservedObject var mbvm = MenuBarViewModel.shared
    
    var body: some View {
        NavigationSplitView(columnVisibility: $mbvm.columnVisibility) {
            // 左侧侧边栏视图
            ButtonToolbarView()
                .navigationTitle("左侧面板")
        } content: {
            // 中间主内容视图
            PreView()
                .navigationTitle("主内容")
        } detail: {
            // 右侧检查器视图
            InspectorView() // 替换为你的右侧检查器实现
                .navigationTitle("检查器")
        }
        .toolbar {
            ToolbarItemGroup(placement: .primaryAction) {
                // 左侧侧边栏切换按钮
                Button {
                    if mbvm.columnVisibility.contains(.sidebar) {
                        mbvm.columnVisibility.remove(.sidebar)
                    } else {
                        mbvm.columnVisibility.insert(.sidebar)
                    }
                } label: {
                    Image(systemName: "sidebar.leading")
                        .font(.system(size: 17))
                }
                
                // 右侧检查器切换按钮
                Button {
                    if mbvm.columnVisibility.contains(.detail) {
                        mbvm.columnVisibility.remove(.detail)
                    } else {
                        mbvm.columnVisibility.insert(.detail)
                    }
                } label: {
                    Image(systemName: "sidebar.trailing")
                        .font(.system(size: 17))
                }
            }
        }
        .windowToolbarStyle(UnifiedWindowToolbarStyle(showsTitle: false))
        .windowStyle(HiddenTitleBarWindowStyle())
    }
}

步骤3:移除子视图中的独立toolbar

删除NoSidebars、LeftSidebars等视图内的.toolbar修饰符,所有工具栏按钮统一由顶层的NavigationSplitView管理。

额外优化

  • 可以直接使用系统原生的侧边栏切换按钮样式:给按钮添加.sidebarToggleStyle(.sidebar),让按钮行为与系统一致。
  • 如果需要自定义侧边栏宽度,可在左侧/右侧视图上添加.frame(minWidth: 100, idealWidth: 150, maxWidth: 300)来控制。

内容的提问来源于stack exchange,提问作者newb

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 12:31:00