一、路由表 和 命名路由
之前写了一篇文章介绍了路由导航及路由传参,文章地址:
现在无论是服务端项目还是前端项目基本都是通过路由来决定资源的访问,而项目如果复杂,路由不能随便写,导航也不能直接写个 Wdiget builder
因此最终我们都是通过路由表
和命名路由
来进行导航
1、路由表
Scaffold
Widget 中有一个构造函数的参数是 routes
,是一个 Map
类型,类型声明如下:
final Map<String, WidgetBuilder> routes;
一个字符串映射一个 WidgetBuilder
字符串就是路由的名称,而映射只需要返回一个 widget builder 即可,这里我们构造这个路由表:
SearchPage
、LoginPage
、SignPage
三个页面的代码不重复,文章最后能够找到,就是三个 widget
final Map<String, WidgetBuilder> _routes = {
'/search': (context) => SearchPage(),
'/login': (context) => LoginPage(),
'/sign': (context, {arguments}) => SignPage(arguments: arguments),
};
上面构造出了路由表,就可以直接配置到 Scalfold
中
2、onGenerateRoute 路由拦截
Scalfold 同时支持一个 onGenerateRoute
的参数,接受一个 Route 工厂函数:
/// {@macro flutter.widgets.widgetsApp.onGenerateRoute}
final RouteFactory onGenerateRoute;
为什么要这么做,从上面的路由表可以看出,'/sign': (context, {arguments}) => SignPage(arguments: arguments),
/sign
这个路由的构造中我们在 builder
中接受了第二个可选命名参数: arguments
如何将 arguments 传递给 widget 的构造函数,并且如何在路由跳转之前做些事情都可以在 onGenerateRoute
中进行
比如下面的方法:
Route _routeGenerator(RouteSettings settings) {
final String name = settings.name;
final Function pageBuilder = this._routes[name];
if (pageBuilder != null) {
if (settings.arguments != null) {
// 如果透传了参数
return MaterialPageRoute(
builder: (context) =>
pageBuilder(context, arguments: settings.arguments));
} else {
// 没有透传参数
return MaterialPageRoute(builder: (context) => pageBuilder(context));
}
}
return MaterialPageRoute(builder: (context) => HomeContent());
}
上面代码中,从拦截到路由之后,首先从路由表中拿到路由的 builder,如果能够拿到 builder,则判断是否存在 RouteSettings,如果存在则直接通关构造函数的 arguments 传递给页面 Page Widget。
这种条件就允许页面 Widget 构造函数中,必须有 arguments
这个参数才可以,比如 /sign
代码如下:
这样的优点在于不需要通过 ModalRoute.of(context).settings.xxx
拿数据。直接映射到 Widget 中
// onGeneate
class SignPage extends StatelessWidget {
final Map arguments;
SignPage({Key key, this.arguments}) : super(key: key) {
// print(this.arguments);
}
@override
Widget build(BuildContext context) {
String tmp = ModalRoute.of(context).settings.arguments.toString();
String tmp2 = this.arguments.toString();
return Scaffold(
appBar: AppBar(
title: Text(tmp),
),
body: Center(child: Text(tmp2)),
);
}
}
需要注意上面的代码,两种方式我都获取了 arguments:
String tmp = ModalRoute.of(context).settings.arguments.toString();
String tmp2 = this.arguments.toString();
3、命名路由导航 Navigator.of(context).pushName
创建好了路由表和拦截就可以进行路由导航:
Navigator.of(context).pushNamed('/search');
此时如果要传值,根据 路由拦截 的方法,可以如下传递:
Navigator.of(context).pushNamed('/login', arguments: {
"title": "透传title",
"name": 'postbird',
'passw': '123456'
});
4、效果:
二、路由替换 Navigator.of(context).pushReplacementNamed
正常我们跳转页面,是通过 Navigator.push
或者 pushNamed
实现的,每次都是把页面压入堆栈,在回退 的时候会回退到上一跳页面
某些场景下我们期望不返回上一条,在跳转吓一跳的时候替换本页面,将上一个页面从堆栈中移除,这时候就需要 Navigator.of(context).pushReplacementNamed
这个方法
FlatButton(
child: Text('SignPage Replacement'),
color: Theme.of(context).buttonColor,
onPressed: () {
Navigator.of(context).pushReplacementNamed('/sign');
},
),
本质上使用和 pushNamed
是一样的,只是效果会不一样:
从上面可以发现,从 home -> login -> sign,然后在 sign 中点击返回按钮的时候,中间不会经过 login,直接就返回 home 了
三、根路由 pushNamedAndRemoveUntil
与上面 pushReplacementNamed 差不多思想,但是场景更激进,比如我需要直接返回首页,之前的所有路由全部干掉,堆栈清空
这种场景下,可以借助 Navigator.of(context).pushNamedAndRemoveUntil
从名字上可以看出来,可以有条件的做一些事情
FlatButton(
child: Text('Return '),
color: Theme.of(context).buttonColor,
onPressed: () {
// 根
Navigator.of(context).pushNamedAndRemoveUntil(
'/',
(route) => route == null,
);
},
)
pushNamedAndRemoveUntil
接受两个参数,第一个是路由名,(这里我们使用了根路由)第二个则是对堆栈中的 route 的处理:
下面的处理中我们清空了 route 全部置为 null,则会路由到 '/' 根路由前的所有 route 都被干掉。
Navigator.of(context).pushNamedAndRemoveUntil(
'/',
(route) => route == null,
);
最终效果:
上面效果中能够发现, home -> login -> sign1 -> sign2 -> sign3 然后在 sign3 中点击 return 的时候,直接返回的 home,中间的路由都被干掉了。
四、完整代码:
1、命名路由和路由组
2、路由替换和路由销毁
原文http://www.ptbird.cn/flutter-route-named-route-list-root-route.html