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