最近改造项目,感觉Flutter路由这块需要打磨打磨,想起来之前好像听说过通过注解来生成路由映射的工具裤,嗯,很快就搜索到阿里写的annotation_route,先start一下,看了下issue,没有对页面分散到各个模块的情况进行处理,看了下issue时间,貌似没有改进的计划,放弃。
只能自己挖井(挖坑)了,不久之前刚学会用Dart Pub Global 创建命令行应用程序。
感觉这个注解应该跟官方的json_annotation很相似,于是立刻下载下来,看源码。
在看源码的过程中,低调大佬做了个ok_route,以及掘金一个小伙伴做了route_generator_repo,都是通过注释,来生成路由映射的解决方案,因为最后呈现方式跟自己构思的有所不同,所以还是决定继续看源码,哈哈哈,感兴趣的同学可以去看看,找到合适自己的路由注解。
看到源码,首先映入眼帘的是
dependencies:
analyzer: any
analyzer主要负责将dart代码转换成为ast(abstract syntax tree),具体是什么意思,我随便一搜索,又是大厂的文章
Flutter动态化,看完感觉如果官方能支持dart代码=》AST=》dart代码的话,你们心心念念的热修复应该就能成了。
之后我又看了下
dependencies:
build_runner_core: any
build_runner: any
在build_runner_core的main.dart,我看到PackageGraph如何对Package的解析。从build_runner中看到了builder执行的过程,本来想另开一篇水一下的,后面看到暴打小女孩已经写过了Flutter 注解处理及代码生成,感兴趣的小伙伴可以自己去看一下。
现在知道了怎么解析项目结构以及引用的模块,知道怎么解析一个dart代码,写法法路由就顺利多了,下面直接上使用手册。
使用
增加引用
添加引用到dev_dependencies,你需要注解的project/packages的pubspec.yaml中
dev_dependencies:
ff_annotation_route: any
执行 flutter packages get
下载
添加注解
空构造
import 'package:ff_annotation_route/ff_annotation_route.dart';
@FFRoute(
name: "fluttercandies://mainpage",
routeName: "MainPage",
)
class MainPage extends StatelessWidget
{
// ...
}
带参数构造
import 'package:ff_annotation_route/ff_annotation_route.dart';
@FFRoute(
name: "fluttercandies://picswiper",
routeName: "PicSwiper",
argumentNames: ["index", "pics"],
showStatusBar: false,
pageRouteType: PageRouteType.transparent)
class PicSwiper extends StatefulWidget {
final int index;
final List<PicSwiperItem> pics;
PicSwiper({this.index, this.pics});
// ...
}
FFRoute
parameter | description | default |
---|---|---|
name | 路由的名字(e.g., "/settings"). | required |
argumentNames | 路由的参数的名字 | - |
showStatusBar | 是否显示状态栏 | true |
routeName | 用于埋点收集数据的页面名字 | '' |
pageRouteType | 路由的类型(material, cupertino, transparent) | - |
生成文件
环境
添加dart的bin的路径到你的系统 $PATH
.
cache\dart-sdk\bin
不清楚的可以看掘金
激活
pub global activate ff_annotation_route
执行命令
你可以到你的项目路径下面执行
ff_annotation_route
你也可以直接执行,并且带上你的项目路径
ff_annotation_route path=
命令参数
使用 parameter=xxx, 使用空格隔开多个参数
参数 | 描述 | 默认 |
---|---|---|
path | 你的项目路径 | 当前路径 |
generateRouteNames | 是否在根项目中的 xxx_route.dart 生成全部路由的名字 | false |
mode | 0或者1, 模式1会生成 xxx_route_helper.dart 来帮助你处理 showStatusBar/routeName/pageRouteType | 0 |
routeSettingsNoArguments | 如果为true, FFRouteSettings 将没有arguments这个参数,这个是主要是为了适配Flutter低版本 | false |
Main.dart
-
如果你设置命令带有参数 mode=1, FFNavigatorObserver/FFRouteSettings 将会生成 在 xxx_route_helper.dart
他们帮助追踪页面和设置状态栏. -
如果你设置命令带有参数 mode=1,FFTransparentPageRoute 将会生成 在 xxx_route_helper.dart
它帮助push一个透明的PageRoute.
Widget build(BuildContext context) {
return OKToast(
child: MaterialApp(
title: 'ff_annotation_route demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
navigatorObservers: [
FFNavigatorObserver(routeChange: (name) {
//you can track page here
print(name);
}, showStatusBarChange: (bool showStatusBar) {
if (showStatusBar) {
SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark);
} else {
SystemChrome.setEnabledSystemUIOverlays([]);
}
})
],
builder: (c, w) {
ScreenUtil.instance =
ScreenUtil(width: 750, height: 1334, allowFontScaling: true)
..init(c);
var data = MediaQuery.of(c);
return MediaQuery(
data: data.copyWith(textScaleFactor: 1.0),
child: w,
);
},
initialRoute: "fluttercandies://mainpage",
onGenerateRoute: (RouteSettings settings) {
var routeResult =
getRouteResult(name: settings.name, arguments: settings.arguments);
if (routeResult.showStatusBar != null ||
routeResult.routeName != null) {
settings = FFRouteSettings(
arguments: settings.arguments,
name: settings.name,
isInitialRoute: settings.isInitialRoute,
routeName: routeResult.routeName,
showStatusBar: routeResult.showStatusBar);
}
var page = routeResult.widget ?? NoRoute();
switch (routeResult.pageRouteType) {
case PageRouteType.material:
return MaterialPageRoute(settings: settings, builder: (c) => page);
case PageRouteType.cupertino:
return CupertinoPageRoute(settings: settings, builder: (c) => page);
case PageRouteType.transparent:
return FFTransparentPageRoute(
settings: settings,
pageBuilder: (BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) =>
page);
default:
return Platform.isIOS
? CupertinoPageRoute(settings: settings, builder: (c) => page)
: MaterialPageRoute(settings: settings, builder: (c) => page);
}
},
));
}
Push
Push name
Navigator.pushNamed(context, "fluttercandies://mainpage");
Push name with arguments
参数应该是一个 Map<String,dynamic>
Navigator.pushNamed(context, "fluttercandies://picswiper",
arguments: {
"index": index,
"pics": listSourceRepository
.map<PicSwiperItem>(
(f) => PicSwiperItem(f.imageUrl, des: f.title))
.toList(),
});
结语
不同于其他的路由注解方案,我加入了对埋点,全屏模式以及路由类型的处理。路由注解方案很多,找到一个合适自己的就好了,欢迎提问题。
最后放上 ff_annotation_route,欢迎加入Flutter Candies,一起生产可爱的Flutter 小糖果(QQ群:181398081)
最最后放上Flutter Candies全家桶,真香。
网友评论