Flutter上线项目实战记录之路由篇
1.应用场景
开发中经常遇到
- 路由跳转时拿不到context怎么办,eg:token失效/异地登录跳转登录页面。
- 获取不到当前路由名称怎么办,eg:点击push推送跳转指定路由,如果已经在当前页面就replace,如果不在就push。
- 注册监听路由跳转,做一些想做的事情,eg:不同路由,显示不同状态栏颜色。
- 等等...
2.解决方案
解决思路:
- MaterialApp的routes属性赋值路由数组,navigatorObservers属性赋值路由监听对象NavigatorManager。
- 在NavigatorManager里实现NavigatorObserver的didPush/didReplace/didPop/didRemove,并记录到路由栈List_mRoutes中。
- 将实时记录的路由跳转,用stream发一个广播,哪里需要哪里注册。
3.具体实现
main.dart
MaterialApp( navigatorObservers:[NavigatorManager.getInstance()], routes:NavigatorManager.configRoutes, ... )
navigator_manager.dart
classNavigatorManagerextendsNavigatorObserver{ /*配置routes*/ staticMapconfigRoutes={ PackageInfoPage.sName:(context)=> SplashPage.sName:(context)=>SplashPage(), LoginPage.sName:(context)=>SplashPage()), MainPage.sName:(context)=>SplashPage(), //... } //当前路由栈 staticList _mRoutes; List getroutes=>_mRoutes; //当前路由 RoutegetcurrentRoute=>_mRoutes[_mRoutes.length-1]; //stream相关 staticStreamController_streamController; StreamControllergetstreamController=>_streamController; //用来路由跳转 staticNavigatorStatenavigator; /*单例给出NavigatorManager*/ staticNavigatorManagernavigatorManager; staticNavigatorManagergetInstance(){ if(navigatorManager==null){ navigatorManager=newNavigatorManager(); _streamController=StreamController.broadcast(); } returnnavigatorManager; } //replace页面 pushReplacementNamed(StringrouteName,[WidgetBuilderbuilder]){ returnnavigator.pushReplacement( CupertinoPageRoute( builder:builder??configRoutes[routeName], settings:RouteSettings(name:routeName), ), ); } //push页面 pushNamed(StringrouteName,[WidgetBuilderbuilder]){ returnnavigator.push( CupertinoPageRoute( builder:builder??configRoutes[routeName], settings:RouteSettings(name:routeName), ), ); } //pop页面 pop ([Tresult]){ navigator.pop(result); } //push一个页面,移除该页面下面所有页面 pushNamedAndRemoveUntil(StringnewRouteName){ returnnavigator.pushNamedAndRemoveUntil(newRouteName,(Route route)=>false); } //当调用Navigator.push时回调 @override voiddidPush(Routeroute,RoutepreviousRoute){ super.didPush(route,previousRoute); if(_mRoutes==null){ _mRoutes=newList (); } //这里过滤调push的是dialog的情况 if(routeisCupertinoPageRoute||routeisMaterialPageRoute){ _mRoutes.add(route); routeObserver(); } } //当调用Navigator.replace时回调 @override voiddidReplace({RoutenewRoute,RouteoldRoute}){ super.didReplace(); if(newRouteisCupertinoPageRoute||newRouteisMaterialPageRoute){ _mRoutes.remove(oldRoute); _mRoutes.add(newRoute); routeObserver(); } } //当调用Navigator.pop时回调 @override voiddidPop(Routeroute,RoutepreviousRoute){ super.didPop(route,previousRoute); if(routeisCupertinoPageRoute||routeisMaterialPageRoute){ _mRoutes.remove(route); routeObserver(); } } @override voiddidRemove(RouteremovedRoute,RouteoldRoute){ super.didRemove(removedRoute,oldRoute); if(removedRouteisCupertinoPageRoute||removedRouteisMaterialPageRoute){ _mRoutes.remove(removedRoute); routeObserver(); } } voidrouteObserver(){ LogUtil.i(sName,'&&路由栈&&'); LogUtil.i(sName,_mRoutes); LogUtil.i(sName,'&&当前路由&&'); LogUtil.i(sName,_mRoutes[_mRoutes.length-1]); //当前页面的navigator,用来路由跳转 navigator=_mRoutes[_mRoutes.length-1].navigator; streamController.sink.add(_mRoutes); } }
4.如何使用
token失效跳转
case401: ToastUtil.showRed('登录失效,请重新登陆'); UserDao.clearAll(); NavigatorManager.getInstance().pushNamedAndRemoveUntil(LoginPage.sName); break;
点击push推送跳转
staticjumpPage(StringpageName,[WidgetBuilderbuilder]){ StringcurrentRouteName=NavigatorManager.getInstance().currentRoute.settings.name; //如果是未登录,不跳转 if(NavigatorManager.getInstance().routes[0].settings.name!=MainPage.sName){ return; } //如果已经是当前页面就replace if(currentRouteName==pageName){ NavigatorManager.getInstance().pushReplacementNamed(pageName,builder); }else{ NavigatorManager.getInstance().pushNamed(pageName,builder); } }
监听路由改变状态栏颜色
classStatusBarUtil{ staticListlightRouteNameList=[ TaskhallPage.sName, //... ]; staticListdarkRoutNameList=[ SplashPage.sName, LoginPage.sName, MainPage.sName, //... ]; staticinit(){ NavigatorManager.getInstance().streamController.stream.listen((state){ setupStatusBar(state[state.length-1]); }) } setupStatusBar(RoutecurrentRoute){ if(lightRouteNameList.contains(currentRoute.settings.name)){ setLight(); }elseif(darkRoutNameList.contains(currentRoute.settings.name)){ setDart(); } } }
完结,撒花