NavigationStack 是一个用状态驱动、类型安全的声明式导航容器,它通过管理视图堆栈和导航路径来实现 SwiftUI 应用中的页面导航(专注于单栏场景)
NavigationStack 需要 iOS 16.0+以上版本支持。
核心要素
- NavigationStack (导航容器)
- │
- ├── 管理 NavigationPath (状态存储)
- │
- ├── 包含 navigationDestination (路由配置)
- │ │
- │ └── 判断数据类型 → 映射对应的视图
- │
- └── 视图层(导航的起点)
复制代码NavigationPath 是导航路径容器,用于管理 NavigationStack 的导航状态和历史记录
navigationDestination 是视图修饰符,用于定义数据类型到目标视图的映射关系,相当于导航系统的路由表
基本用法
1、简单页面跳转
可NavigationStack配合NavigationLink实现(不需要使用NavigationPath记录、管理路径)- struct ContentView: View {
- var body: some View {
- NavigationStack {
- List {
- NavigationLink("前往详情页", value: "详情内容")
- NavigationLink("设置", value: "设置页面")
- }
- .navigationDestination(for: String.self) { value in
- DetailView(content: value)
- }
- }
- }
- }
- struct DetailView: View {
- let content: String
- var body: some View {
- Text("详情: \(content)")
- .navigationTitle("详情页")
- }
- }
复制代码 2、简单页面跳转:多类型路由映射
很多时候,navigationDestination映射的value类型并非只有一种:- struct Test: View {
- var body: some View {
- NavigationStack {
- List {
- // 使用 value 参数 - 必须遵循 Hashable(swift值类型数据默认遵循Hashable协议)
- NavigationLink("使用 value", value: "字符串值")
- NavigationLink("使用数字", value: 42)
- }
- .navigationDestination(for: String.self) { value in
- Text("字符串值: \(value)")
- }
- .navigationDestination(for: Int.self) { value in
- Text("整数值: \(value)")
- }
- }
- }
- }
复制代码 3、简单页面跳转:多类型路由映射2
也可使用枚举管理多种数据类型:- //注意value类型,需要遵循Hashable
- enum Route: Hashable {
- case product(Int)
- case profile(String)
- case settings
- }
- struct MultiTypeNavigationView: View {
- var body: some View {
- NavigationStack {
- VStack(spacing: 20) {
- NavigationLink("产品详情", value: Route.product(123))
- NavigationLink("用户资料", value: Route.profile("张三"))
- NavigationLink("设置", value: Route.settings)
- }
- .navigationDestination(for: Route.self) { route in
- switch route {
- case .product(let id):
- ProductDetailView(productId: id)
- case .profile(let username):
- ProfileView(username: username)
- case .settings:
- SettingsView()
- }
- }
- }
- }
- }
复制代码 4、多层页面跳转
可使用NavigationStack、NavigationPath实现
NavigationPath提供了以下方法用于管理路径:
append() : 跳转到新页面
removeLast(): 返回上一页
removeLast(n): 返回前n页
removeAll(): 返回首页
count: 显示当前导航深度
Codable: 实现状态持久化和深度链接
5、Hashable 的作用
导航必需:NavigationLink 的 value 参数必须遵循 Hashable
路径管理:NavigationPath 依赖 Hashable 来跟踪导航状态
唯一性判断:用于比较两个实例是否代表相同的导航目标
5.1、NavigationLink 的 Hashable 要求
- struct NavigationLinkRequirement: View {
- var body: some View {
- NavigationStack {
- List {
- // ✅ 形式1:使用 value 参数 - 必须遵循 Hashable
- NavigationLink("使用 value", value: "字符串值")
- NavigationLink("使用数字", value: 42)
-
- // ❌ 这会导致编译错误,因为 MyData 不遵循 Hashable
- // NavigationLink("无效", value: MyData())
-
- // ✅ 形式2:使用 destination 参数 - 不需要 Hashable
- NavigationLink("使用 destination") {
- MyCustomView()
- }
-
- // ✅ 传统形式 - 不需要 Hashable
- NavigationLink("传统形式", destination: Text("目标视图"))
- }
- .navigationDestination(for: String.self) { value in
- Text("字符串值: \(value)")
- }
- .navigationDestination(for: Int.self) { value in
- Text("整数值: \(value)")
- }
- }
- }
- }
- // ❌ 不遵循 Hashable 的类型
- struct MyData {
- let content: String
- }
- struct MyCustomView: View {
- var body: some View {
- Text("自定义视图")
- }
- }
复制代码 5.2、NavigationPath 的 Hashable 要求
- struct NavigationPathExample: View {
- @State private var path = NavigationPath()
-
- var body: some View {
- NavigationStack(path: $path) {
- VStack(spacing: 20) {
- Text("NavigationPath 演示")
- .font(.title)
-
- Button("添加字符串") {
- // ✅ 字符串遵循 Hashable
- path.append("新页面")
- }
-
- Button("添加整数") {
- // ✅ 整数遵循 Hashable
- path.append(100)
- }
-
- Button("添加自定义类型") {
- // ✅ 只要遵循 Hashable 就可以
- path.append(MyHashableData(name: "测试", id: 1))
- }
-
- // ❌ 这会导致运行时错误
- Button("添加非 Hashable 类型(会崩溃)") {
- // path.append(MyData()) // 取消注释会崩溃
- }
-
- Button("查看路径深度: \(path.count)") {
- print("当前路径深度: \(path.count)")
- }
-
- Button("返回") {
- if !path.isEmpty {
- path.removeLast()
- }
- }
-
- Button("返回根视图") {
- path = NavigationPath() // 重置路径
- }
- }
- .navigationDestination(for: String.self) { value in
- Text("字符串页面: \(value)")
- }
- .navigationDestination(for: Int.self) { value in
- Text("整数页面: \(value)")
- }
- .navigationDestination(for: MyHashableData.self) { data in
- Text("自定义数据: \(data.name) - \(data.id)")
- }
- }
- }
- }
- // ✅ 遵循 Hashable 的自定义类型
- struct MyHashableData: Hashable {
- let name: String
- let id: Int
- }
复制代码 6、导航栏UI自定义
NavigationStack 导航结构图:
[code]NavigationStack (容器层) │ ├──
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |