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

NavigationView内SwiftUI Toolbar按钮失效问题求助

问题:NavigationView中Toolbar按钮在窗口调整后异常禁用

我使用NavigationView和多个NavigationLink编写了代码,其中一个链接对应的视图带有Toolbar修饰符。出现的问题是:首次进入第一个NavigationLink时Toolbar按钮正常工作,但切换到第二个NavigationLink后,将窗口调整至最小尺寸,再返回第一个NavigationLink,点击Toolbar的>>按钮展开隐藏按钮时,这些按钮处于禁用状态,只有将窗口恢复至全屏才能重新启用。

希望了解该bug的原因、修复方案,或者有没有其他方式实现「侧边栏包含多个标签页,可切换并为用户打开不同视图」的需求。

Bug重现步骤

  • 运行代码
  • 进入第二个标签页
  • 将窗口调整至最小尺寸
  • 返回第一个标签页
  • 点击Toolbar的>>按钮查看隐藏按钮,此时按钮处于禁用状态

代码示例

enum TabItems: String, CaseIterable, Identifiable {
    case first
    case second
    case third

    var id: String {
        return rawValue
    }
}

struct ContentView: View {
    @State private var selection: TabItems? = TabItems.first
    
    var body: some View {
        NavigationView {
            List {
                ForEach(TabItems.allCases) { item in
                    NavigationLink(
                        destination: tabView(tab: item),
                        tag: item,
                        selection: $selection,
                        label: { Text(item.id) }
                    )
                }
            }
        }
    }
    
    @ViewBuilder
    private func tabView(tab: TabItems) -> some View {
        switch tab {
        case .first:
            Text(tab.id)
                .toolbar {
                    ForEach(0 ..< 10) { _ in
                        Button(
                            action: { print("button pressed") },
                            label: {
                                Label(
                                    title: { Text("Button") },
                                    icon: { Image(systemName: "plus") }
                                )
                            }
                        )
                    }
                }
        case .second:
            Text(tab.id)
        case .third:
            Text(tab.id)
        }
    }
}

分析与修复方案

问题原因

这是SwiftUI中NavigationView与Toolbar布局联动的已知bug:当视图切换后窗口尺寸发生变化,Toolbar的隐藏按钮容器未正确重新计算按钮的启用状态,导致布局更新时按钮的交互状态未同步,最终出现禁用的情况。

修复方案1:为Toolbar按钮添加唯一标识

通过给每个Toolbar按钮添加明确的唯一ID,确保SwiftUI在视图更新时能正确识别每个按钮的身份,避免状态混淆。修改后的代码如下:

case .first:
    Text(tab.id)
        .toolbar {
            // 给ForEach添加id参数,同时给每个Button设置唯一id
            ForEach(0 ..< 10, id: \.self) { index in
                Button(
                    action: { print("button pressed") },
                    label: {
                        Label(
                            title: { Text("Button") },
                            icon: { Image(systemName: "plus") }
                        )
                    }
                )
                .id("toolbar-button-\(index)")
            }
        }

修复方案2:使用NavigationStack替代NavigationView

如果你的项目支持iOS 16+/macOS 13+,建议使用新一代的NavigationStack组件,它修复了NavigationView的诸多旧bug,布局和状态同步更稳定。修改后的ContentView代码:

struct ContentView: View {
    @State private var selection: TabItems? = TabItems.first
    
    var body: some View {
        NavigationStack(path: $selection) {
            List {
                ForEach(TabItems.allCases) { item in
                    NavigationLink(
                        value: item,
                        label: { Text(item.id) }
                    )
                }
            }
            .navigationDestination(for: TabItems.self) { item in
                tabView(tab: item)
            }
        }
    }
    
    // 原tabView方法保持不变
}

替代实现方式:使用TabView的sidebar样式

如果你的核心需求是「侧边栏多标签切换」,可以直接使用TabView结合.sidebar样式,这种方式更贴合需求,也能避免NavigationView的导航栈状态问题:

struct ContentView: View {
    @State private var selectedTab: TabItems = .first
    
    var body: some View {
        TabView(selection: $selectedTab) {
            Text(TabItems.first.rawValue)
                .toolbar {
                    ForEach(0 ..< 10, id: \.self) { index in
                        Button(action: { print("button pressed") }) {
                            Label("Button", systemImage: "plus")
                        }
                    }
                }
                .tabItem { Text(TabItems.first.rawValue) }
                .tag(TabItems.first)
            
            Text(TabItems.second.rawValue)
                .tabItem { Text(TabItems.second.rawValue) }
                .tag(TabItems.second)
            
            Text(TabItems.third.rawValue)
                .tabItem { Text(TabItems.third.rawValue) }
                .tag(TabItems.third)
        }
        .tabViewStyle(.sidebar)
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 08:57:08