SwiftUI 路由管理 NavigationStack

2023-03-10  本文已影响0人  激动的厨师

因为对moya框架的使用,给了我启发,花点时间封装了下 NavigationStack 的路由管理。不多说,上代码:

先定义个Path的枚举,对应APP的每个页面,可带参数(moya的API也是这样处理的)
enum SFNavigationPath:Hashable{
    
    case loginPath
    case baseTabbarPath
    
    case baoBiaoPath
    
    
    case yewuPath
    
    
    case homePath
    
    case customersPath
    case customerDetailPath
    case customerAddOrEidtPath
    
    case newsPath
    case newsDetailPath
    case newsListPath
    
    
    case testPath(_ index:Int)//带参数类型测试
    case testPath2
    
    
    func pageParamView() -> some View{
        switch self {
        case .loginPath:
            return AnyView(LoginView())
        case .baseTabbarPath:
            return AnyView(BaseTabbar())
        case .baoBiaoPath:
            return AnyView(BaoBiaoView())
        case .yewuPath:
            return AnyView(YewuView())
        case .homePath:
            return AnyView(HomeSpace())
        case .customersPath:
            return AnyView(CustomersView())
        case .newsPath:
            return AnyView(NewsView())
        case .testPath(let index):
            return AnyView(TestPage(index: index))
        case .testPath2:
            return AnyView(TestPage2())
        default:
            return AnyView(TestPage2())
        }
    }
}

再定义一个SFNavigationDelegate 协议代理,协议方法 有push...等这些一看就懂。
protocol SFNavigationDelegate{
    associatedtype Route = SFNavigationPath
    func push(_ path:Route)
    func pop()
    func popToRoot()
    func popUntil(_ path:Route)
}

继续做一个View分类用来 导航页面用,具体就是用到的时候,需要实现调用,当然也可以自己实现navigationDestination,具体看业务需求吧。
extension View{
    //返回默认,或者简单参数的页面
    func pathNormalPageView() -> some View {
        self.navigationDestination(for: SFNavigationPath.self) { path in
            path.pageParamView()
        }
    }
    
    //如果复杂参数,可以用这个
    func pathCustPageView(@ViewBuilder destination: @escaping (_ path:SFNavigationPath) -> some View) -> some View{
        self.navigationDestination(for: SFNavigationPath.self, destination: destination)
    }
}

最后写一个manger 遵守协议来管理导航


class PathManager:ObservableObject,SFNavigationDelegate{
    @Published var manager:[SFNavigationPath] = []
    
    func push(_ path: SFNavigationPath) {
        self.manager.append(path)
    }
    
    func pop() {
        self.manager.removeLast()
    }
    
    func popToRoot() {
        self.manager.removeAll()
    }
    
    func popUntil(_ path: SFNavigationPath) {
        if self.manager.last != path {
            self.manager.removeLast()
            popUntil(path)
        }
    }
    
}

使用方法:pathManager.manager传入 NavigationStack,然后 注入.environmentObject(pathManager)

@StateObject var pathManager = PathManager()
    var body: some View {
        NavigationStack(path: $pathManager.manager){
            ZStack(alignment: .bottom) {
                TabView(selection: $viewModel.selectedTab) {
                    BaoBiaoView()
                        .tag(SFTabbarType.chartBarType)
                    YewuView()
                        .tag(SFTabbarType.yewuBarType)
                    HomeSpace()
                        .tag(SFTabbarType.homeBarType)
                    CustomersView()
                        .tag(SFTabbarType.custBarType)
                    NewsView()
                        .tag(SFTabbarType.newsBarType)
                }
                .accentColor(.red)
                .background(.red)
                .toast(isPresenting: $viewModel.showMsg, text: viewModel.msg)
                
                SFTabbarView().onAppear{//刷新消息数量
                    viewModel.getNewsNumber()
                }
            }
            .ignoresSafeArea(.all,edges: .bottom)
            .environmentObject(viewModel)
            .navigationBarTitleDisplayMode(.inline)
        }
        .environmentObject(pathManager)
@EnvironmentObject var pathManger:PathManager
    var body: some View {
        VStack {
            SFNavigationBar(showBackBtn:false,title: "报表"){
                
            }
            BaseListView(viewModel: viewModel) {
                ForEach(viewModel.datas, id: \.self) { item in
                    VStack(spacing: 0){
                        HStack {
                            Text("点击了\(item)")
                            Text("点击了\(item)")
                        }
                        .foregroundColor(.black)
                        .padding(.all,15)
                        .frame(minWidth: screenWidth,maxWidth: .infinity)
                        .background(.white)
                        Divider()
                    }
                    .onTapGesture {
                        pathManger.push(.testPath2)
                    }
                }
            }
            .pathNormalPageView()
        }
        .background(viewModel.bgColor)
    }

如果带参数可以这样用:

pathManger.push(.testPath(100))

如果是复杂参数可以这样用:

.pathCustPageView { path in
                if path == .testPath2{
                    //TODO
                }
            }
上一篇 下一篇

猜你喜欢

热点阅读