Flutter路由传递参数及解析实现
上⼀篇介绍了使⽤路由来实现页⾯的跳转,从⽽简化页⾯之间的耦合,并可以实现路由拦截。在实际开发中,我们经常会需要在页⾯跳转的时候携带路由参数,典型的例⼦就是从列表到详情页的时候,需要携带详情的 id,以便详情页获取对应的数据。同时,有些时候还需要返回时携带参数返回上⼀级,以便上级页⾯根据返回结果更新。本篇将介绍这两种情形的实现。
Navigator 的 push 和 pop⽅法
Navigator导航器的push和pop⽅法可以携带参数在页⾯间传递,其他变形的⽅法也⼀样。pushNamed⽅法原型如下:
Future<T?> pushNamed<T extends Object?>(
String routeName, {
Object? arguments,
}) {
return push<T>(_routeNamed<T>(routeName, arguments: arguments)!);
}
除了routeName的命名路由以外,还有个可选参数arguments⽤于在路由页⾯传递参数。pop⽅法也⼀样:
void pop<T extends Object?>([ T? result ]) {
//...
flutter pub
}
可以携带⼀个result回传到上级页⾯。
代码实现
我们使⽤⼀个列表跳转到详情页来演⽰路由参数获取(列表构建⽂章请看)。点击列表⾏时携带列表数据项的 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传递到详情页。
@override
Widget 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(String()),
],
),
)
],
)
,
),
onTap: () async {
Map<String, dynamic> routeParams = {'id': id};
var arguments = await Navigator.of(context)
.pushNamed(RouterTable.dynamicDetail, arguments: routeParams);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text("从动态${(arguments as Map<String, dynamic>)['id']}返回"),
));
},
);
}
这⾥还使⽤了⼀个arguments变量接收导航返回的参数,导航若有返回参数,会返回⼀个Future对象,使⽤await即可接收。然后在使⽤as转换为实际的类型进⾏使⽤。
在详情页中,Flutter 提供了⼀个ModalRoute的类从当前上下⽂获取路由配置参数,代码如下所⽰:
class DynamicDetail extends StatelessWidget {
const DynamicDetail({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
Map<String, dynamic> 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<bool>对象,若为false,则不会返回。若为true,则返回上⼀级。这⾥我们调⽤了携带参数的pop⽅法以便将参数回传。实际这⾥往往做⼀些其他处理,例如表单没有保存时询问是否确认离开,还有⼴⼤电商的活动页询问你是“忍痛离开”或是“再看⼀会”的处理。
最终效果
最终运⾏效果如下图所⽰,详情页获取到了id参数,返回的时候也接收到了对应的id。
路由参数拦截
路由参数可以通过onGenerateRoute拦截进⾏额外处理,⽰例代码如下。需要注意,这⾥仅仅是⽰例,由于settings。arguments 可能为任意类型,因此可能会导致转换失败。实际业务中最好是约定路由参数传递类型,避免参数形式不统⼀导致异常出现。
static Route onGenerateRoute<T extends Object>(RouteSettings settings) {
var arguments = settings.arguments as Map<String, dynamic>;
if (arguments != null) {
arguments['event'] = '路由拦截增加的参数';
}
RouteSettings newSettings =
return CupertinoPageRoute<T>(
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路由传递参数及解析实现的⽂章就介绍到这了。希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。