Flutter 路由模块化 - flutter_mixin_router
库说明
flutter_mixin_router
库与其说是一个路由框架,还不如称之为一种思想,利于Dart
的mixin特性,参考flutter
源码中WidgetsFlutterBinding
所总结出来的。
库本身代码核心类仅仅只有两个MixinRouterContainer
、MixinRouterInterceptContainer
。前者用于粘合各模块的PageRoute
列表,后者用于拦截PageRoute
跳转,
比如拦截用户未登录情况下打开个人中心页面。
使用说明
项目结构如下:
--- Home : 大厅业务模块
---- home_page_1.dart : 大厅页面1
---- home_page_2.dart : 大厅页面2
---- home_router_table.dart : 使用mixin_router创建的文件,用于聚合该模块所有路由,即:大厅子路由表
--- Mine : 个人业务模块
---- mine_page.dart : 个人页面1
---- mine_router_table.dart : 使用mixin_router创建的文件,用于聚合该模块所有路由,即:个人子路由表
main.dart : 启动文件(entry-point)
app_router_center.dart : 使用mixin_router创建的文件,用于聚合所有模块(大厅业务模块 和 个人业务模块),即:路由总表
页面相关的代码这里就不再说明了,重点文件main.dart
、app_router_center.dart
、home_router_table.dart
和 mine_router_table.dart
。
main.dart:
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Mixin Route Test',
//配置初始化路由,建议定义静态字段
initialRoute: '/home_page_1',
//从路由总表中获取App所有路由
routes: AppRouterCenter.share.installRouters(),
);
}
}
app_router_center.dart
//使用mixin机制,将各路由模块组装
class AppRouterCenter extends MixinRouterInterceptContainer
with HomeRouterTable, MineRouterTable {
AppRouterCenter._();
static final AppRouterCenter _instance = AppRouterCenter._();
static AppRouterCenter get share => _instance;
}
home_router_table.dart
//使用mixin定义大厅路由子表
mixin HomeRouterTable on MixinRouterContainer {
@override
Map<String, WidgetBuilder> installRouters() {
Map<String, WidgetBuilder> superRouteList = super.installRouters();
//添加本模块路由
Map<String, WidgetBuilder> routeList = {
'/home_page_1': (context) => Home1Page(),
'/home_page_2': (context) => Home2Page(),
};
routeList.addAll(superRouteList);
return routeList;
}
}
mine_router_table.dart
//使用mixin定义个人路由子表,与大厅路由子表定义不同,此处继承MixinRouterInterceptContainer,支持拦截
//而 MixinRouterInterceptContainer extends MixinRouterContainer
mixin MineRouterTable on MixinRouterInterceptContainer {
@override
Map<String, WidgetBuilder> installRouters() {
//注册路由拦截,return true 表示消费本次跳转,否则进行路由跳转
registerRouteInterceptor('/mine_page', (context, pageName, pushType,
{arguments, predicate}) {
if (isLogin) {
return false;
}
print('toLogin');
return true;
});
Map<String, WidgetBuilder> superRouteList = super.installRouters();
//添加本模块路由
Map<String, WidgetBuilder> routeList = {
'/mine_page': (context) => MinePage(),
};
routeList.addAll(superRouteList);
return routeList;
}
}
打开指定页面:
//可配置打开router的方式,pushName, pushReplacementNamed...
//可配置打开router的参数
AppRouteCenter.share.openPage(context, '/mine_page', ...)
页面参数获取
String? name = getMixinArg(context)?['name'];
int? age = getMixinArg(context)?['age'];
扩展
-
内置扩展
如果
AppRouterCenter
extendsUriRouterInterceptContainer
,则上面打开指定页面的方式,可以支持Uri,AppRouteCenter.share.urlToPage(context, 'appscheme://mine_page?name=1&age=2') String? name = getMixinArg(context)?['name']; //通过uri的方式打开页面,参数都是string类型 String? age = getMixinArg(context)?['age'];
-
自定义扩展
开发者可参考
UriRouterInterceptContainer
自定Container,并使得AppRouterCenter
extends自定义Container
到此为止,flutter_mixin_router说明已经结束,但是使用该方案,还是会存在大量的模板代码,但是可以利用Dart的build_runner
生成代码,简化 flutter_mixin_router
的使用。
集成
# 以下xxx替换成最新版本号
dependencies:
...
#添加
flutter_mixin_router_ann: xxx
#添加
flutter_mixin_router: xxx
dev_dependencies:
...
#添加
build_runner: 2.1.8
#添加
flutter_mixin_router_gen: xxx
使用
项目结构说明:
--- Home : 大厅业务模块
---- home_page_1.dart : 大厅页面1
---- home_page_2.dart : 大厅页面2
--- Mine : 个人业务模块
---- mine_page.dart : 个人页面1
main.dart : 启动文件(entry-point)
app_router_center.dart : 使用mixin_router创建的文件,用于聚合所有模块(大厅业务模块 和 个人业务模块),即:路由总表
跟 flutter_mixin_router
说明中的项目结构对比,每个模块不再需要定义子路由表文件,改由flutter_mixin_router_gen
生成。
使用flutter_mixin_router_gen
需要关注三点:总路由表 app_router_center.dart
文件编写、页面路由注册、拦截路由注册。
app_router_center.dart:
//定义大厅子路由表名称
const String HOME_ROUTER_TABLE = 'HomeRouterTable';
//定义个人子路由表名称
const String MINE_ROUTER_TABLE = 'MineRouterTable';
//向总路由表注册各子路由表
//tDescription: 仅仅作为生成类的注释
@RouterTableList(
tableList: [
RouterTable(tName: HOME_ROUTER_TABLE, tDescription: '大厅路由模块'),
RouterTable(tName: MINE_ROUTER_TABLE, tDescription: '个人路由模块'),
],
)
//with HomeRouterTable, MineRouterTable,即上面声明的两个路由表的名字
class AppRouterCenter extends UriRouterInterceptContainer
with HomeRouterTable, MineRouterTable {
AppRouterCenter._();
static final AppRouterCenter _instance = AppRouterCenter._();
static AppRouterCenter get share => _instance;
}
页面注册:
//定义路由页面,tName 代表该路由属于哪个路由子表
@MixinRoute(tName: HOME_ROUTER_TABLE, path: '/home_page_1')
class Home1Page extends StatelessWidget {
...
}
拦截路由注册:
@MixinRoute(tName: MINE_ROUTER_TABLE, path: '/mine_page')
class MinePage extends StatelessWidget {
const MinePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
...
}
}
//定义路由拦截,该注解使用在方法上,方法有以下两个约束:
//1、作为顶级元素声明在文件中
//2、方法的参数和返回值固定
@MixinInterceptRoute(tName: MINE_ROUTER_TABLE, path: '/mine_page')
bool interceptorMinePage(context, pageName, pushType, {arguments, predicate}) {
if (isLogin) {
return false;
}
print('toLogin');
return true;
}
生成文件
# 清除增量编译缓存
flutter packages pub run build_runner clean
# 重新生成代码
flutter packages pub run build_runner build --delete-conflicting-outputs
生成的文件与被RouterTableList
注解的文件X
同级。
转载自:https://juejin.cn/post/7076284057423708197