对于Flutter路由的使用,从入门到深入一般有以下几个阶段:
- 初步了解到Flutter中是用路由(Route)表示页面(Page)。使用基本的MaterialPageRoute方式进行页面操作。
- 学会使用Navigator来完成路由操作。
- 学会使用命名路(Named Route)由来完成路由的管理与操作。
以上三个阶段属于官方的基本知识。 - 使用三方Fluro完成路由的管理与操作。
- 使用注解方式完成路由的管理与操作。(闲鱼有三方)
首先假设我们的App组织架构如下
- login模块
- home模块
- buy模块
我们需要高效的管理现有页面路由,并兼顾后续页面扩展。
新建一个Flutter工程
在pubspec.yaml文件中添加Fluro三方
dependencies:
flutter:
sdk: flutter
# 路由管理三方Fluro
# https://github.com/theyakka/fluro
fluro: ^1.6.3
.yaml文件对齐有严格要求
建议每个添加的三方库都附上简要说明和网址
修改基本代码
修改Home页面布局为中间一个按钮
添加一个Buy页面,布局也是中间一个按钮
源码lib1
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FlatButton(
onPressed: () => print('进行跳转操作'),
child: Text('点我 跳转到buy页面'),
),
),
);
}
}
根据作者的说明我们先初始化Router
final router = Router();
接下来我们浏览一下Router的源码,大致浏览都提供了哪些方法。
...假装看懂了,还是看作者说明吧。作者说明对新手也不怎么友好。。
好像有一行很短的样子,先看这一行。
You can also manually push to a route yourself. To do so:
router.navigateTo(context, "/users/1234", transition: TransitionType.fadeIn);
翻看一下源代码
///
Future navigateTo(BuildContext context, String path,
{bool replace = false,
bool clearStack = false,
TransitionType transition,
Duration transitionDuration = const Duration(milliseconds: 250),
RouteTransitionsBuilder transitionBuilder}) {
....
return future;
}
if (route != null) {
if (clearStack) {
future =
Navigator.pushAndRemoveUntil(context, route, (check) => false);
} else {
future = replace
? Navigator.pushReplacement(context, route)
: Navigator.push(context, route);
}
...
}
默认的clearStack是false,replace是false,那么
future = Navigator.push(context, route);
这就是非常基础的Navigator用法了。
context是直接传入的参数,那么route是如何得到呢。
RouteMatch routeMatch = matchRoute(context, path,
transitionType: transition,
transitionsBuilder: transitionBuilder,
transitionDuration: transitionDuration);
Route<dynamic> route = routeMatch.route;
可以看到通过传入path等参数,通过使用matchRoute方法,我们获得到了route。暂时不用关心该方法的内部,大概的也能猜到path就是我们使用命名路由,注册路由表时的路由名。此时我们还没有使用命名路由注册路由表。
让我们直接使用作者给我们的说明代码
router.navigateTo(context, "/users/1234", transition: TransitionType.fadeIn);
看看报错信息
flutter: No registered route was found to handle '/users/1234'.
flutter: 进行跳转操作
[VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception:
No registered route was found to handle '/users/1234'
null
提示我们路由没有注册。这个提示是fluro给出的。
是否就是使用命名路由时的注册路由表呢?我们添加一下代码
routes: {
'/users/1234': (context) => BuyPage(),
},
错误依然存在。那么让我们来看看fluro说的registered在哪里执行。
查看fluro的源码
/// The tree structure that stores the defined routes
final RouteTree _routeTree = RouteTree();
...
/// Creates a [PageRoute] definition for the passed [RouteHandler].
/// You can optionally provide a default transition type.
void define(String routePath,
{@required Handler handler, TransitionType transitionType}) {
_routeTree.addRoute(
AppRoute(routePath, handler, transitionType: transitionType),
);
}
可以看到作者的解释
RouteTree 用来存储已经定义的路由
difine方法创建PageRoute
那么我们需要调用define方法来定义(registered)路由。
Widget build(BuildContext context) {
...
router.define('/users/1234', handler: XXX);
...
}
那么这个handler是什么呢?查看一下源码
class Handler {
Handler({this.type = HandlerType.route, this.handlerFunc});
final HandlerType type;
final HandlerFunc handlerFunc;
}
...
typedef Widget HandlerFunc(
BuildContext context, Map<String, List<String>> parameters);
Handler是构造成HandlerType.route类型的类,需要传入this.handlerFunc参数
HandlerFunc是一个Widget,是BuildContext context, Map<String, List<String>> parameters的typedef定义。因此,我们要传送一个BuildContext context, Map<String, List<String>> parameters给Handler当参数。
让我们构造一个buyPageHandler,参考作者的代码,返回值是一个路由Wiget(BuyPage())
var buyPageHandler = Handler(
handlerFunc: (BuildContext context, Map<String, dynamic> params) {
return BuyPage();
});
此时,修改路由定义代码
router.define('/users/1234', handler: buyPageHandler);
运行程序 查看代码
可以看到,点击HomePage的按钮已经正常能够跳转到BuyPage。
让我们回一下为了,实现跳转Fluro都做了哪些事情。
- 初始化了一个router
- 定义了一个buyPageHandler。可以传入params,返回一个route类型的Widget.
- 定义了一个router,需要传入name和handler两个参数
- 使用navigateTo,传入name,进行页面跳转。
至此Fluro的最基本用法已经说明完毕。让我们回到最初的那个问题
如果我们想在BuyPage跳转到HomePage页面,那么刚才的4个步骤我们需要一个不落的重新一遍。重新就意味着可以抽离相同的代码。比如抽离route的初始化。
如果我们想在LoginPage页面也跳转到HomePage页面,那么步骤 2 3也可以抽离出来单独定义,从而进行复用。我们可以清晰的看到步骤 2 3是跳转目标页面的定义,而与到底从哪个页面跳转来无关。
如何进行抽离呢?作者的说明里有这么两句话。。
下篇继续写。。