SwiftUI 导航:通过 NavigationStack 和 NavigationDestination 实现路径管理

server/2025/1/12 10:26:05/

在 SwiftUI 开发中,实现灵活且功能丰富的导航系统是构建优秀用户界面的关键。本文将深入解析一段 SwiftUI 代码,展示如何利用 NavigationStack 和枚举来实现多界面导航,并在不同界面之间传递参数。

代码整体概述

这段代码构建了一个具有多个界面的导航系统,通过 NavigationStack 管理导航路径,使用枚举来定义不同的界面状态,并在界面跳转时传递各种类型的参数。同时,代码还包含了日志记录功能,用于打印当前显示的界面信息。

代码详细解析

1. 定义 Screen 枚举

enum Screen: Hashable {case homecase secondView(message: String)case thirdView(data: Int)case fourthView(name: String)
}

Screen 枚举用于表示应用中的不同界面状态。每个枚举成员代表一个特定的界面,并且可以附带不同类型的参数。例如,secondView 携带一个 String 类型的消息,thirdView 携带一个 Int 类型的数据,fourthView 携带一个 String 类型的名字。

2. ContentView 视图

struct ContentView: View {@State private var path: [Screen] = [] // 路径栈var body: some View {NavigationStack(path: $path) {VStack {Button("Go to Second View with Message") {path.append(.secondView(message: "Hello from Home"))}}.navigationTitle("Home").navigationDestination(for: Screen.self) { screen inswitch screen {case.secondView(let message):SecondView(path: $path, message: message)case.thirdView(let data):ThirdView(path: $path, data: data)case.fourthView(let name):FourthView(path: $path, name: name)default:Text("Unknown View")}}.onChange(of: path, { oldValue, newValue inlogCurrentScreen(newValue)})}}// 记录当前界面日志private func logCurrentScreen(_ path: [Screen]) {if let currentScreen = path.last {switch currentScreen {case.home:print("Current Screen: Home")case.secondView(let message):print("Current Screen: Second View with message '\(message)'")case.thirdView(let data):print("Current Screen: Third View with data \(data)")case.fourthView(let name):print("Current Screen: Fourth View with name '\(name)'")}} else {print("Current Screen: Home (Root)")}}
}
  • @State private var path: [Screen] = []:定义一个状态变量 path,用于存储导航路径。它是一个 Screen 类型的数组,记录了用户在应用中访问过的界面。
  • NavigationStack(path: $path):创建一个导航栈,并将 path 绑定到导航栈中。这样,导航栈的状态就与 path 变量同步。
  • Button("Go to Second View with Message"):一个按钮,点击时将 .secondView(message: "Hello from Home") 添加到 path 中,触发导航到 SecondView 并传递消息。
  • navigationDestination(for: Screen.self):根据 path 中的 Screen 枚举值,显示对应的目标视图。通过 switch 语句,根据不同的枚举成员创建相应的视图,并传递所需的参数。
  • .onChange(of: path):当 path 发生变化时,调用 logCurrentScreen 函数,打印当前显示的界面信息。

3. SecondView 视图

struct SecondView: View {@Binding var path: [Screen]let message: String // 从上一个界面传递的值var body: some View {VStack {Text("Message: \(message)")Button("Go to Third View with Data") {path.append(.thirdView(data: 42)) // 传递整数数据}}.navigationTitle("Second View")}
}
  • @Binding var path: [Screen]:接收来自 ContentView 的 path 绑定,以便在该视图中操作导航路径。
  • let message: String:接收从上一个界面(ContentView)传递过来的消息。
  • Button("Go to Third View with Data"):点击该按钮时,将 .thirdView(data: 42) 添加到 path中,导航到 ThirdView 并传递整数数据。

4. ThirdView 视图

struct ThirdView: View {@Binding var path: [Screen]let data: Int // 从上一个界面传递的值var body: some View {VStack {Text("Data: \(data)")Button("Go to Fourth View with Name") {path.append(.fourthView(name: "Alice")) // 传递字符串}}.navigationTitle("Third View")}
}

与 SecondView 类似,ThirdView 接收 path 绑定和来自上一个界面的整数数据。按钮点击时,将 .fourthView(name: "Alice") 添加到 path 中,导航到 FourthView 并传递字符串。

5. FourthView 视图

struct FourthView: View {@Binding var path: [Screen]let name: String // 从上一个界面传递的值var body: some View {VStack {Text("Name: \(name)")Button("Go Back to Second View") {if let index = path.firstIndex(where: {if case.secondView = $0 { return true }return false}) {path.removeLast(path.count - index - 1)}}Button("Go Back to Root View") {path.removeAll() // 清空路径,返回到根界面}}.navigationTitle("Fourth View")}
}
  • @Binding var path: [Screen] 和 let name: String:接收 path 绑定和来自上一个界面的名字。
  • Button("Go Back to Second View"):通过查找 path 中 secondView 枚举成员的索引,移除从当前位置到 secondView 之间的所有界面,实现返回 SecondView 的功能。
  • Button("Go Back to Root View"):点击该按钮时,清空 path 数组,返回到根界面(ContentView

http://www.ppmy.cn/server/157739.html

相关文章

小程序相关

1.右侧胶囊宽度&#xff0c;胶囊和文本重合问题 // #ifdef MP-WEIXIN // 获取胶囊左边界坐标 const { left } uni.getMenuButtonBoundingClientRect() this.rightSafeArea left px // #endif//给到你的内容宽度 <view :style"{max-width:rightSafeArea}"> …

C/C++ 数据结构与算法【查找】 线性表查找、树表的查找、散列表的查找详细解析【日常学习,考研必备】带图+详细代码

一、查找的基本概念 1&#xff09;在哪里找&#xff1f; 2&#xff09;什么查找&#xff1f; 3&#xff09;查找成功与否&#xff1f; 4&#xff09;查找的目的是什么&#xff1f; 5&#xff09;查找表怎么分类&#xff1f; 6&#xff09;如何评价查找算法&#xff1f; 7&…

python3GUI--大屏可视化-传染病督导平台 By:PyQt5

文章目录 一&#xff0e;前言二&#xff0e;预览三&#xff0e;软件组成&开发心得1.样式&使用方法2.左侧表格实现3.设计4.学习5.体验效果 四&#xff0e;代码分享1.环形渐变进度组件2.自定义图片的背景组件 五&#xff0e;总结 大小&#xff1a;60.9 M&#xff0c;软件…

ip归属地和手机号是一个地址吗

IP归属地和手机号是两个常被提及但本质上截然不同的概念。它们各自代表着不同的信息&#xff0c;反映了不同的技术和应用场景。本文将从定义、原理、应用场景以及两者之间的关系等方面&#xff0c;详细探讨IP归属地和手机号是否是一个地址的问题。 一、IP归属地和手机号的定义 …

世优波塔数字人 AI 大屏再升级:让智能展厅讲解触手可及

近日&#xff0c;世优波塔大屏AI数字人再度升级&#xff0c;将数字人技术与大屏交互推向了新的高度&#xff0c;为用户带来了全方位的卓越体验&#xff0c;让人工智能不断重塑我们的生活与工作方式。 新形象&#xff1a;数字人的独特魅力 高精度的数字人形象一直是波塔智能体…

在idea中配置多个版本的jdk

问题&#xff1a;有时候有好几个项目&#xff0c;不同的项目用的是不同版本的jdk。 在oracle官网下载多个版本的jdk https://www.oracle.com/cn/java/technologies/downloads/选择exe版本安装 如果只在idea里使用的话&#xff0c;就不需要配置环境变量了。只需要在项目结构里a…

支持selenium的chrome driver更新到131.0.6778.264

最近chrome释放新版本&#xff1a;131.0.6778.264 如果运行selenium自动化测试出现以下问题&#xff0c;是需要升级chromedriver才可以解决的。 selenium.common.exceptions.SessionNotCreatedException: Message: session not created: This version of ChromeDriver only s…

/src/utils/request.ts:axios 请求封装,适用于需要统一处理请求和响应的场景

文章目录 数据结构解释1. 核心功能2. 代码结构分析请求拦截器响应拦截器 3. 改进建议4. 总结 console.log(Intercepted Response:, JSON.stringify(response));{"data": {"code": 0,"msg": "成功","data": {"id":…