300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > Flutter 封装fluro路由框架 提供路由 实现父子页面信息互传等功能

Flutter 封装fluro路由框架 提供路由 实现父子页面信息互传等功能

时间:2021-01-03 07:34:06

相关推荐

Flutter 封装fluro路由框架 提供路由 实现父子页面信息互传等功能

参考这篇,讲的也比较不错 =====Flutter入门之(fluro路由跳转框架)

要实现的功能

push -> 可以不传递/传递 params 到next 页面(路由)pop -> 可以直接pop / 可以pop时携带params 返回上一级页面(路由)replace -> 干掉当前路由reset -> 重置路由clearStack fluro提供的清空当前路由栈的参数选项最好是用一个导航管理类的静态方法来调用, 使用方便

需要知道的

首先, fluro也是基于Flutter自己的导航模块封装的, 一切的基准还是基于Future , 类似于RN的Promise, 所以,我们可以把 push的行为理解成一个异步函数,

比如这样使用

change(BuildContext context) async {print('welcomt ======= + ');var res = await NavigationUtils.push(context, AppRouterList.test1, transition: TransitionType.fadeIn, params: {"we":"lff","you":"wll"});print('welcomt ======= + ' + res.toString());}

启动push, 执行异步函数(此时就算进入了异步函数, 如果你使用async/await, 那么就处于 一直在 await的过程中)当下一级页面pop执行, 此时的才会给这一次的push行为给出一个明确Future完成态结果, 此时上一级页面发起的 await 函数 才能继续走下去,有人会问, 那我push 执行了, 就一直在await, 那不是卡住了后面函数的执行了吗?比如上面的使用代码, 第二个打印就要一直等,等到下一个页面pop了, 才会执行.我的理解是, 是的会卡住, 但是这本来也是合理的,当你执行一个push动作以后, 一定是离开当前页面,而且当前页面也不该再执行任何操作, 而且await能确保Flutter在push到下一个页面的时候, 不会因为其他什么耗时操作而影响到push的UI动作, 也保证转场动画页面切换的流程性(个人理解,有问题请多指教)

封装Fluro

基本上, 网上有很多封装的思路, 我也是初学,然后借鉴别人的, 按照自己习惯进行了部分修改

需要的几个类

1.AppRouter => 这个是一个全局的路由对象类, 用来设置Fluro的配置,以及AppRouterList 路由列表的注册导入

2.AppRouterList => 用来记录各个路由path, 以及提供以路由注册的方法来配置各个路由

3.NavigationUtils => 这个就是导航工具类, 一般配置好以后, 我们就主要使用该类, 来进行静态函数调用, push/pop/replace 等

直接上代码

代码里注释还算详细…吧

AppRouter.dart

import 'package:ebankhome/page/common/PageNotFound.dart';import 'package:ebankhome/router/AppRouterList.dart';/// -------------------------------/// Created with Flutter Dart File./// User tianNanYiHao@/// Date: -08-07/// Time: 13:24/// Des: 路由类/// -------------------------------import 'package:fluro/fluro.dart';import 'package:flutter/material.dart';/// [AppRouter] 路由类/// 提供路由注册/拦截/404等功能class AppRouter {/// 全局路由对象static Router router;/// 初始化路由类基本信息static void configureRoutes() {Router router = Router();/// 指定路由错误的跳转页面router.notFoundHandler = Handler(handlerFunc:(BuildContext context, Map<String, List<String>> parameters) {debugPrint('---------paeg 404 ------------');return PageNotFound();});/// 路由批量导入AppRouterList().initRouter(router);AppRouter.router = router;}}

AppRouterList.dart

import 'package:ebankhome/page/common/BottomNavigationPage.dart';import 'package:ebankhome/page/common/Test1.dart';import 'package:ebankhome/page/common/Test2.dart';import 'package:ebankhome/page/common/Test3.dart';import 'package:ebankhome/page/common/Welcome.dart';import 'package:ebankhome/page/cunstomer/Customer.dart';import 'package:ebankhome/page/home/Home.dart';import 'package:ebankhome/page/login/LogIn.dart';import 'package:ebankhome/page/login/Register.dart';import 'package:ebankhome/page/my/My.dart';/// -------------------------------/// Created with Flutter Dart File./// User tianNanYiHao@/// Date: -08-07/// Time: 13:36/// Des: 路由列表类, 新增的路由在此添加/// -------------------------------import 'package:fluro/fluro.dart';/// [AppRouterList] 路由列表类class AppRouterList {static String pagenNotFound = 'pagenNotFound'; //未找到 404static String welcome = 'welcome';static String BottomNavgationPage = 'BottomNavgationPage'; // 基础页static String login = 'login';static String register = 'register';static String home = 'home';static String customer = 'customer';static String my = 'my';static String test1 = 'test1';static String test2 = 'test2';static String test3 = 'test3';/// 注册路由列表 - 新增的路由页面在此添加...void initRouter(Router router) {router.define(welcome, handler: Handler(handlerFunc: (_, params) => Welcome()));router.define(BottomNavgationPage, handler: Handler(handlerFunc: (_, params) => BottomNavigationPage()));/// *********************************** 登录/注册/忘记密码等... ***********************************router.define(login, handler: Handler(handlerFunc: (_, params) => Login()));router.define(register, handler: Handler(handlerFunc: (_, params) => Register()));/// *********************************** 首页相关 ***********************************router.define(home, handler: Handler(handlerFunc: (_, params) => Home()));/// *********************************** 客户相关 ***********************************router.define(customer, handler: Handler(handlerFunc: (_, params) => Customer()));/// *********************************** 工作台相关 ***********************************router.define(my, handler: Handler(handlerFunc: (_, params) => My()));router.define(test1, handler: Handler(handlerFunc: (_, params) => Test1(params: params,)));router.define(test2, handler: Handler(handlerFunc: (_, params) => Test2()));router.define(test3, handler: Handler(handlerFunc: (_, params) => Test3()));}}

NavigationUtils.dart

import 'package:ebankhome/router/AppRouter.dart';/// -------------------------------/// Created with Flutter Dart File./// User tianNanYiHao@/// Date: -08-07/// Time: 13:27/// Des: 路由控制类/// -------------------------------import 'package:flutter/material.dart';import 'package:fluro/fluro.dart';import 'dart:async';import 'dart:convert';class NavigationUtils {/// *********************************** 静态属性 ***********************************/// 全局导航栈的内部路由下标 计数 (私有的静态属性,防止外部篡改)static int _navigationStackIndex = 0; // 0 代表路由栈下标为0的路由, 既是栈底,也是栈顶./// *********************************** 私有的静态基础导航函数 ***********************************/// 导航栈下标 addstatic _navigationStackIndexPlus(bool replace, bool clearStack) {if (replace) {// replace 不变NavigationUtils._navigationStackIndex = NavigationUtils._navigationStackIndex;} else if (clearStack) {// clearStack 下标归零(navigate.to 的新的路由既为栈底,也为栈底 对应下标就是0)NavigationUtils._navigationStackIndex = 0;} else {// 导航跳转后. 栈内路由数增加1NavigationUtils._navigationStackIndex += 1;}}/// 导航栈下标 minusstatic _navigationStackIndexMinus(bool replace, bool clearStack) {if (replace) {// replace 不变NavigationUtils._navigationStackIndex = NavigationUtils._navigationStackIndex;} else if (clearStack) {// clearStack 下标归零(navigate.to 的新的路由既为栈底,也为栈底 对应下标就是0)NavigationUtils._navigationStackIndex = 0;} else {// 导航跳转失败, 撤回跳转前新增的计数if (NavigationUtils._navigationStackIndex > 0) {NavigationUtils._navigationStackIndex -= 1;}}}/// 讲路由路径和需要传递的参数进行拼装/// 返回格式为 {params:String} 将Map<T>类型的params json序列化传递出去static _routerNameMixWithParams(String routerName, Map<String, dynamic> params) {if (params == null || params.isEmpty) {return routerName;} else {routerName = '${routerName}';String jsonParams = jsonEncode(params);print(jsonParams);return routerName + '?' + "params=${jsonParams}";}}/// [replace] 是否关闭当前页面 (当前页面从内存中释放 dispose)/// [clearStack] 是否关闭当前页面及之前的路由栈(讲当前页面及之前的所有从内存中释放 dispose)/// [transition] 切换动画类型/// [params] push时. 可以传递一些信息给下级页面static Future<dynamic> _navigateTo(BuildContext context, String path,{bool replace = false,bool clearStack = false,Map<String, dynamic> params,TransitionType transition = TransitionType.cupertino}) async {final com = Completer();Future future = com.future;try {FocusScope.of(context).requestFocus(FocusNode());// 导航栈下标计数_navigationStackIndexPlus(replace, clearStack);path = _routerNameMixWithParams(path, params);// 只有pop执行时, 才会给出明确状态的Futrue<res>,否则 该await将会一直等待,Map<String, dynamic> res = await AppRouter.router.navigateTo(context, path, replace: replace, clearStack: clearStack, transition: transition);plete(res); // 这一行的执行, 就需要等到下级页面pop了, 才能被触发. 在此之前, await会一直等待,(在页面跳转的时候,确实需要一个同步操作来保证)} catch (error) {// 撤销计数_navigationStackIndexMinus(replace, clearStack);// pleteError(false);plete(false); // 跳转失败,也resolve一个false, 方便外部不用每个调用都要catch异常处理, 只需要知道返回False 意味着跳转失败即可}return future;}/// *********************************** 辅助函数 ***********************************/// 打印路由树../// 暂时没看出来有啥用static printRouterTree() {AppRouter.router.printTree();}/// 获取当前路由栈的栈顶下标static getNavigationStackIndex() {return NavigationUtils._navigationStackIndex;}/// *********************************** 导航方法 ***********************************/// push/// [path] 目标路由名/// [transition] 切换动画类型/// [params] push时. 可以传递一些信息给下级页面static push(BuildContext context, String path,{Map<String, dynamic> params, TransitionType transition = TransitionType.cupertino}) {debugPrint('push前, 当前路由index = ${NavigationUtils._navigationStackIndex.toString()} | (传递的参数为${params.toString()})');return _navigateTo(context, path, params: params, replace: false, clearStack: false, transition: transition);}/// pop///[params] pop时, 可以携带一些信息返回给上级页面static pop(BuildContext context, {Map<String, dynamic> params}) {debugPrint('pop前, 当前路由index = ${NavigationUtils._navigationStackIndex.toString()} | (回传的参数为${params.toString()})');// 导航栈拦截判断是否允许popif (NavigationUtils._navigationStackIndex == 0) {debugPrint('===== 检测到路由栈已到栈底,阻止pop行为 ======');return;}// 允许pop - 栈内路由数删除1if (NavigationUtils._navigationStackIndex > 0) {NavigationUtils._navigationStackIndex -= 1;}// 允许pop - 执行po操作FocusScope.of(context).requestFocus(FocusNode());Navigator.pop(context, params ?? {});debugPrint('pop后, 当前路由index ' + NavigationUtils._navigationStackIndex.toString());}/// replace/// [path] 目标路由名/// [transition] 切换动画类型/// 跳转到新的路由页面,同时清除当前被跳转的路由static replace(BuildContext context, String path, {TransitionType transition = TransitionType.cupertino}) {debugPrint('replace前, 当前路由index = ${NavigationUtils._navigationStackIndex.toString()} ');return _navigateTo(context, path, replace: true, clearStack: false, transition: transition);}/// clearStack/// [path] 目标路由名/// [transition] 切换动画类型/// 跳转到新的路由页面,同时清空当前路由栈static clearStackAndEarlier(BuildContext context, String path,{TransitionType transition = TransitionType.cupertino}) {debugPrint('clearStack前, 当前路由index = ${NavigationUtils._navigationStackIndex.toString()}');return _navigateTo(context, path, replace: false, clearStack: true, transition: transition);}/// rest/// 重置路由.... 待实现.../// 重置路由.... 待实现.../// 重置路由.... 待实现...static void reset(BuildContext context, List<String> paths, int lastPageIndex) {}}

几个问题解释

返回值问题

这里我人为规定了返回的 Future的几个状态下的数据

var res = await NavigationUtils.push(context, AppRouterList.test1, transition: TransitionType.fadeIn, params: {"we":"lff","you":"wll"});

如果说,pop返回不携带任何params. 那么res 就是 {}

如果说,pop返回携带了部分信息, 那么就是返回 Map<String,dynamic> 类型的对象

如果说,push出现了异常失败了, 那么res 就是false,

所以说, 在使用中,完全可以不用管 catch 的事情… 也算是偷懒吧, 毕竟以后页面多了, 处处都要去写 async{ try{}catch(err){}}, 也是够呛

当然, 如果不用 async / await 方式去写, 直接用.then((res){…}) 那也是可以的, 而且不用关心返回的res的话, 那就和RN 里面的用法没啥区别了, 比如直接写

NavigationUtils.push(context, AppRouterList.test1, transition: TransitionType.fadeIn, params: {"we":"lff","you":"wll"});

也是可以的

2.push 要传参怎么搞?

参考的链接里面没有明确说怎么接收, 其实了解Flutter StatefulWidget的也知道, 我们通过其构造函数, 可以来接受一些参数, 或者,我们用可选参数的形式更为妥当

所以这么搞

先找到 我们的AppRouterList, 在我们用Fluro 来注册路由的时候我们有个handle方法,

router.define(my, handler: Handler(handlerFunc: (_, params) => My()));router.define(test1, handler: Handler(handlerFunc: (_, params) => Test1(params: params,)));router.define(test2, handler: Handler(handlerFunc: (_, params) => Test2()));router.define(test3, handler: Handler(handlerFunc: (_, params) => Test3()));

那么在Test1.dart 中

我们要手动添加一个构造函数,给她一个可选的参数 params即可,

Test1({dynamic params}) {debugPrint('Test1 ---!!!-- 构造函数+ ${params}');}

漏了初始化的问题,

在Flutter启动的时候, 要实例化一个路由实例,

并且将路由导入到 onGenerateRoute 中…

class MyApp extends StatefulWidget {// This widget is the root of your application.MyApp() {// 初始化路由AppRouter.configureRoutes();// 初始化尺寸的全局变量DeviceUtils.initDeviceW_H();}@override_MyApp createState() => _MyApp();}class _MyApp extends State<StatefulWidget> {@overridevoid initState() {// TODO: implement initStatesuper.initState();}@overrideWidget build(BuildContext context) {return MaterialApp(title: '哒哒哒哒哒哒',theme: ThemeData(),home: Welcome(),//home: BottomNavigationPage(),// 生成路由onGenerateRoute: AppRouter.router.generator,);}}

( 当然你也可以添加一命名构造函数用来专门接收, 但是就需要在 router.define()中,修改对应的路由构造函数, - - -表述的不咋地, 可以不用管我的瞎猜瞎想)

后续需要改进的

目前提供了一个路由栈下标函数, 用来处理安卓手机 虚拟返回键问题, 但是我还没具体去实现… 等要做到那个功能的时候, 再回来编辑一下具体代码…reset 重置路由我还没实现该功能, 以后回来补……

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。