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

NavigationSplitView内NavigationStack路径变更时被清空问题咨询

我在WindowGroup中编写了如下SidebarSelection视图:

struct SidebarSelection: View {
    
    @State var selection: Int?
    @State var path: [Int] = []
    
    var body: some View {
        NavigationSplitView {
            List(1...20, id: \.self, selection: $selection) { number in
                    Text("I like \(number)")
            }
        } detail: {
            NavigationStack(path: $path) {
                VStack {
                    Image(systemName: "x.squareroot")
                        .imageScale(.large)
                        .foregroundColor(.accentColor)
                    Text("This is the NavigationStack root")
                }
                .padding()
                .navigationDestination(for: Int.self) { number in
                    Text("You chose \(number)")
                }
            }
        }
        .onChange(of: selection) { newValue in
            print("You clicked \(newValue ?? 0)")
            if let newValue {
                path.append(newValue)
                print("New path \(path)")
            }
        }
        .onChange(of: path) { newValue in
            print("Path changed to \(path)")
        }
    }
}

在macOS上运行后,依次点击:

  • „I like 5“
  • „I like 6“
  • „I like 7“

预期结果

详情视图依次显示:

  • „You chose 5“
  • „You chose 6“
  • „You chose 7“

控制台输出应为:

You clicked 5
New path [5]
Path changed to [5]
You clicked 6
New path [5, 6]
Path changed to [5, 6]
You clicked 7
New path [5, 6, 7]
Path changed to [5, 6, 7]

实际结果

详情视图显示:

  • „You chose 5“
  • „This is the NavigationStack root“
  • „You chose 7“

控制台实际输出:

New path [5]
Path changed to [5]
You clicked 6
New path [5, 6]
Path changed to []
You clicked 7
New path [7]
Path changed to [7]

我认为这是一个Bug,已提交反馈并在Apple论坛提问半年,但问题仍未解决。请问我是否操作有误?是什么清空了path,以及如何在NavigationSplitView中正确使用NavigationStack?


问题分析与解决方案

原因

你遇到的path被清空的情况,并非系统Bug,而是macOS上NavigationSplitView的默认行为:
当通过侧边栏的selection绑定切换选项时,系统会自动重置详情区域的NavigationStack路径,目的是让侧边栏的选择与详情视图的根内容一一对应,这是符合分栏视图的设计逻辑的——侧边栏负责切换不同的详情根内容,而非在同一个导航栈中叠加页面。

你的操作逻辑违背了这个设计:手动向path中追加值,而系统会在你选择新的侧边栏项时,自动重置path为空,导致中间步骤的视图跳回根页面。

修复方案

方案1:匹配分栏视图的设计逻辑(推荐)

将path.append(newValue)改为直接赋值path = [newValue],让每次侧边栏选择都直接切换详情视图的根页面:

.onChange(of: selection) { newValue in
    print("You clicked \(newValue ?? 0)")
    if let newValue {
        path = [newValue] // 替换为直接赋值,而非追加
        print("New path \(path)")
    }
}

修改后,每次点击侧边栏项,详情视图会直接显示对应的You chose X页面,不会出现path被清空、视图跳回根页面的问题,完全符合NavigationSplitView的预期行为。

方案2:保留导航栈叠加需求

如果你的实际场景确实需要在详情视图的导航栈中叠加页面(比如从侧边栏选择项后,在详情页内继续导航,同时保留侧边栏切换的栈),可以通过NavigationLink替代selection绑定的方式实现:

struct SidebarSelection: View {
    @State var path: [Int] = []
    @State var selection: Int? // 保留选中状态
    
    var body: some View {
        NavigationSplitView {
            List(1...20, id: \.self, selection: $selection) { number in
                NavigationLink(value: number) {
                    Text("I like \(number)")
                }
                .tag(number)
            }
        } detail: {
            NavigationStack(path: $path) {
                VStack {
                    Image(systemName: "x.squareroot")
                        .imageScale(.large)
                        .foregroundColor(.accentColor)
                    Text("This is the NavigationStack root")
                }
                .padding()
                .navigationDestination(for: Int.self) { number in
                    Text("You chose \(number)")
                }
            }
        }
        .onChange(of: path) { newValue in
            print("Path changed to \(path)")
        }
    }
}

这种方式下,点击侧边栏的NavigationLink会自动将值推入path,macOS不会自动重置栈,同时侧边栏的选中状态也能正常保留。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 23:25:03