当前位置: 首页 > news >正文

【iOS】SwiftUI 路由管理(NavigationStack)

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)
            }
        }
    }

相关文章:

  • 深入理解 Linux 的 top 命令:实时监控系统性能
  • Unity 解决TMP_Text 文字显示异常的问题
  • 手势调控屏幕亮度:Python + OpenCV + Mediapipe 打造智能交互体验
  • 记事本(基于JAVAGUI界面)
  • 一次模拟Windows挖矿病毒应急响应的流程及思路
  • Linux系统管理与编程05:网络管理番外篇
  • 一篇最全Python 爬虫超详细讲解(零基础入门,适合小白)
  • AUTOSAR Communication Services - COM:(一)COM相关功能、API整理与序列图
  • 文献阅读篇#1:C会/期刊的改进YOLO论文应放弃即插即用,至少要学会简单融合拼接(1)
  • 逐光之路:我在特种设备作业考试中的成长蜕变
  • Joker靶机实战攻略
  • 逻辑派G1 6层高速板学习
  • 连接不上雷电模拟器,adb连接不上问题的解决办法
  • Billu_b0x靶机实战攻略
  • JS逆向案例-HIKVISION-视频监控的前端密码加密分析
  • 分享一个项目中遇到的一个算法题
  • SPI 总线协议
  • Pytest项目_day01(HTTP接口)
  • 微服务即时通信系统---(五)框架学习
  • 【Spring】第四弹:基于XML文件注入Bean对象
  • 车主质疑零跑汽车撞车后AEB未触发、气囊未弹出,4S店:其把油门当刹车
  • 【社论】打破“隐形高墙”,让老年人更好融入社会
  • 中国乒协坚决抵制恶意造谣,刘国梁21日将前往多哈参加国际乒联会议
  • 重庆发布经济犯罪案件接报警电子地图,企业可查询导航属地经侦服务点
  • 山东鄄城发生一起交通事故,造成4人死亡、2人受伤
  • 山西省委常委李金科添新职