Flutter上线项目实战记录之路由篇
2019-09-06 14:20
1061 查看
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
class NavigatorManager extends NavigatorObserver { /* 配置routes */ static Map<String, WidgetBuilder> configRoutes = { PackageInfoPage.sName: (context) => SplashPage.sName: (context) => SplashPage(), LoginPage.sName: (context) => SplashPage()), MainPage.sName: (context) => SplashPage(), //... } // 当前路由栈 static List<Route> _mRoutes; List<Route> get routes => _mRoutes; // 当前路由 Route get currentRoute => _mRoutes[_mRoutes.length - 1]; // stream相关 static StreamController _streamController; StreamController get streamController=> _streamController; // 用来路由跳转 static NavigatorState navigator; /* 单例给出NavigatorManager */ static NavigatorManager navigatorManager; static NavigatorManager getInstance() { if (navigatorManager == null) { navigatorManager = new NavigatorManager(); _streamController = StreamController.broadcast(); } return navigatorManager; } // replace 页面 pushReplacementNamed(String routeName, [WidgetBuilder builder]) { return navigator.pushReplacement( CupertinoPageRoute( builder: builder ?? configRoutes[routeName], settings: RouteSettings(name: routeName), ), ); } // push 页面 pushNamed(String routeName, [WidgetBuilder builder]) { return navigator.push( CupertinoPageRoute( builder: builder ?? configRoutes[routeName], settings: RouteSettings(name: routeName), ), ); } // pop 页面 pop<T extends Object>([T result]) { navigator.pop(result); } // push一个页面, 移除该页面下面所有页面 pushNamedAndRemoveUntil(String newRouteName) { return navigator.pushNamedAndRemoveUntil(newRouteName, (Route<dynamic> route) => false); } // 当调用Navigator.push时回调 @override void didPush(Route route, Route previousRoute) { super.didPush(route, previousRoute); if (_mRoutes == null) { _mRoutes = new List<Route>(); } // 这里过滤调push的是dialog的情况 if (route is CupertinoPageRoute || route is MaterialPageRoute) { _mRoutes.add(route); routeObserver(); } } // 当调用Navigator.replace时回调 @override void didReplace({Route newRoute, Route oldRoute}) { super.didReplace(); if (newRoute is CupertinoPageRoute || newRoute is MaterialPageRoute) { _mRoutes.remove(oldRoute); _mRoutes.add(newRoute); routeObserver(); } } // 当调用Navigator.pop时回调 @override void didPop(Route route, Route previousRoute) { super.didPop(route, previousRoute); if (route is CupertinoPageRoute || route is MaterialPageRoute) { _mRoutes.remove(route); routeObserver(); } } @override void didRemove(Route removedRoute, Route oldRoute) { super.didRemove(removedRoute, oldRoute); if (removedRoute is CupertinoPageRoute || removedRoute is MaterialPageRoute) { _mRoutes.remove(removedRoute); routeObserver(); } } void routeObserver() { 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失效跳转
case 401: ToastUtil.showRed('登录失效,请重新登陆'); UserDao.clearAll(); NavigatorManager.getInstance().pushNamedAndRemoveUntil(LoginPage.sName); break;
点击push推送跳转
static jumpPage(String pageName, [WidgetBuilder builder]) { String currentRouteName = 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); } }
监听路由改变状态栏颜色
class StatusBarUtil { static List<String> lightRouteNameList = [ TaskhallPage.sName, //... ]; static List darkRoutNameList = [ SplashPage.sName, LoginPage.sName, MainPage.sName, //... ]; static init() { NavigatorManager.getInstance().streamController.stream.listen((state) { setupStatusBar(state[state.length - 1]); }) } setupStatusBar(Route currentRoute) { if (lightRouteNameList.contains(currentRoute.settings.name)) { setLight(); } else if (darkRoutNameList.contains(currentRoute.settings.name)) { setDart(); } } }
完结,撒花🎉
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。
您可能感兴趣的文章:
相关文章推荐
- 最新对接真实数据 从0开发前后端分离企业级上线项目实战
- Node.js项目实战-构建可扩展的Web应用(第一版):10 为Node.js应用上线做准备
- Vue2+VueRouter2+Webpack+Axios 构建项目实战(四)调整 App.vue 和 router 路由
- 架构之路--实战项目记录(二) 忘记数据库 开始抽象
- 【LEFT JOIN 实战记录】是否纳入市级预算项目概览界面
- Vue2+VueRouter2+webpack 构建项目实战(三)配置路由,整俩页面先
- maven实战(五)maven管理项目优秀博客地址记录
- Vue2+VueRouter2+webpack 构建项目实战(三)配置路由,整俩页面先
- tensorflow机器学习项目实战记录(聚类)
- Node.js实战项目(二)----路由优化
- osgi实战项目(osmp)一步一步玩转osgi之服务发现与服务路由(5)
- 记录实战小项目之基于yolo的目标检测web api实现
- mpvue小程序实战项目开发记录篇(二)
- 敏捷开发与项目管理实战之敏捷需求分析(装载记录有用的文章)
- 实战项目-小说网站开发过程中难点记录(1)
- iOS - RxSwift 项目实战记录
- Ionic 入门与实战之第三章:Ionic 项目结构以及路由配置
- 记录 用android studio 打包flutter项目
- 架构之路--实战项目记录
- mpvue小程序实战项目开发记录篇(三)