Flutter路由传递参数及解析实现
上一篇Flutter页面路由及404路由拦截实现介绍了使用路由来实现页面的跳转,从而简化页面之间的耦合,并可以实现路由拦截。在实际开发中,我们经常会需要在页面跳转的时候携带路由参数,典型的例子就是从列表到详情页的时候,需要携带详情的 id,以便详情页获取对应的数据。同时,有些时候还需要返回时携带参数返回上一级,以便上级页面根据返回结果更新。本篇将介绍这两种情形的实现。Navigator 的 push 和 pop方法
Navigator
导航器的 push
和 pop
方法可以携带参数在页面间传递,其他变形的方法也一样。pushNamed
方法原型如下:FuturepushNamed (String routeName, {Object? arguments,}) {return push (_routeNamed (routeName, arguments: arguments)!); }
【Flutter路由传递参数及解析实现】除了
routeName
的命名路由以外,还有个可选参数 arguments
用于在路由页面传递参数。pop
方法也一样:void pop([ T? result ]) {//...}
可以携带一个
result
回传到上级页面。代码实现 我们使用一个列表跳转到详情页来演示路由参数获取(列表构建文章请看Flutter 入门与实战(五):来一个图文并茂的列表)。点击列表行时携带列表数据项的 id 跳转到详情页。从详情页返回时再把该 id 回传。列表项的 Widget 新增了一个 id属性,由构建列表时初始化得到。
class DynamicItem extends StatelessWidget {final int id; final String title; final String imageUrl; final int viewCount; static const double ITEM_HEIGHT = 100; static const double TITLE_HEIGHT = 80; static const double MARGIN_SIZE = 10; const DynamicItem(this.id, this.title, this.imageUrl, this.viewCount,{Key key}): super(key: key); //...}
列表的容器使用
GestureDetector
包裹,以便响应点击事件。 onTap
方法定义为一个 async
方法,以便使用 await
获取导航返回时的参数,并使用一个 SnackBar
显示返回的 id
。这里 pushNamed
携带了一个 Map
对象将列表的 id
传递到详情页。@overrideWidget build(BuildContext context) {return GestureDetector(child: Container(margin: EdgeInsets.all(MARGIN_SIZE),child: Row(crossAxisAlignment: CrossAxisAlignment.start,children: [_imageWrapper(this.imageUrl),Expanded(child: Column(crossAxisAlignment: CrossAxisAlignment.start,children: [_titleWrapper(context, this.title),_viewCountWrapper(this.viewCount.toString()),],),)],),),onTap: () async {Map routeParams = {'id': id}; var arguments = await Navigator.of(context).pushNamed(RouterTable.dynamicDetail, arguments: routeParams); ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("从动态${(arguments as Map)['id']}返回"),)); },); }
这里还使用了一个
arguments
变量 接收导航返回的参数,导航若有返回参数,会返回一个 Future
对象,使用 await
即可接收。然后在使用 as
转换为实际的类型进行使用。在详情页中,Flutter 提供了一个
ModalRoute
的类从当前上下文获取路由配置参数,代码如下所示:class DynamicDetail extends StatelessWidget {const DynamicDetail({Key key}) : super(key: key); @overrideWidget build(BuildContext context) {Map routeParams =ModalRoute.of(context).settings?.arguments; return WillPopScope(child: Scaffold(appBar: AppBar(title: Text('动态详情'),brightness: Brightness.dark,),body: Center(child: Text("产品 id: ${routeParams['id']}"),),),onWillPop: () async {Navigator.of(context).pop({'id': routeParams['id']}); return true; },); }}
实际上这个
ModalRoute.of(context).settings
就是我们上一篇路由拦截中的onGenerateRoute
的 settings
参数,因此假设我们需要增加额外的路由参数(例如全局参数),则可以在 onGenerateRoute
方法中重新组装路由参数。这里有个地方需要注意,因为返回时要携带参数,因此我们需要拦截返回响应事件,这时候整个组件可以使用
WillPopScope
包裹,该方法带有两个参数:child
:子组件,即原有的页面组件;onWillPop
:返回前拦截处理,返回一个Future
对象,若为false
,则不会返回。若为true
,则返回上一级。这里我们调用了 携带参数的pop
方法以便将参数回传。实际这里往往做一些其他处理,例如表单没有保存时询问是否确认离开,还有广大电商的活动页询问你是“忍痛离开”或是“再看一会”的处理。
id
参数,返回的时候也接收到了对应的 id
。路由参数拦截 路由参数可以通过 onGenerateRoute拦截进行额外处理,示例代码如下。需要注意,这里仅仅是示例,由于 settings。arguments 可能为任意类型,因此可能会导致转换失败。实际业务中最好是约定路由参数传递类型,避免参数形式不统一导致异常出现。
static Route onGenerateRoute(RouteSettings settings) {var arguments = settings.arguments as Map; if (arguments != null) {arguments['event'] = '路由拦截增加的参数'; }RouteSettings newSettings =settings.copyWith(name: settings.name, arguments: arguments); return CupertinoPageRoute (settings: newSettings,builder: (context) {String name = settings.name; if (routeTables[name] == null) {name = notFoundPath; }Widget widget = routeTables[name](context); return widget; },); }
总结 本篇介绍了路由参数的传递示例以及路由拦截后参数修改,在实际过程中一般是往下级传递路由参数,需要尽量避免来回传参来实现数据传递导致上下级页面耦合严重,最好通过状态管理实现。目前这种路由管理也会存在一定的不便之处,比如无法像网页的 url 一样在路径名传递可变参数,以及无法控制页面跳转的转场动画。在 pub 上
fluro
路由管理非常流行,下一篇介绍如何使用 fluro
实现页面路由。到此这篇关于Flutter路由传递参数及解析实现的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
推荐阅读
- Android事件传递源码分析
- Flutter的ListView
- 运用flutter|运用flutter 构建一个发布版(release)APK
- Flutter自定义view|Flutter自定义view —— 闯关进度条
- day|day 28 设置路由表
- layui-admin.view方法传递
- Flutter|Flutter SwiftUI React 对比
- flutter设置沉浸式状态栏
- Angular|Angular 用service 在组件间传递数据
- 2019-12-02|2019-12-02 flutter的环境配置