前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Flutter 路由参数传递及接收

Flutter 路由参数传递及接收

作者头像
用户7043603
发布2022-02-24 22:19:27
1.2K0
发布2022-02-24 22:19:27
举报

Navigator 的 push 和 pop方法

Navigator 导航器的 pushpop 方法可以携带参数在页面间传递,其他变形的方法也一样。pushNamed 方法原型如下:

代码语言:javascript
复制
Future<T?> pushNamed<T extends Object?>(
  String routeName, {
  Object? arguments,
}) {
  return push<T>(_routeNamed<T>(routeName, arguments: arguments)!);
}

除了 routeName 的命名路由以外,还有个可选参数 arguments 用于在路由页面传递参数。pop 方法也一样:

代码语言:javascript
复制
void pop<T extends Object?>([ T? result ]) {
  //...
}

可以携带一个 result 回传到上级页面。

代码实现

我们使用一个列表跳转到详情页来演示路由参数获取(列表构建文章请看Flutter 入门与实战(五):来一个图文并茂的列表)。点击列表行时携带列表数据项的 id 跳转到详情页。从详情页返回时再把该 id 回传。列表项的 Widget 新增了一个 id属性,由构建列表时初始化得到。

代码语言:javascript
复制
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传递到详情页。

代码语言:javascript
复制
@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(this.viewCount.toString()),
              ],
            ),
          )
        ],
      ),
    ),
    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的类从当前上下文获取路由配置参数,代码如下所示:

代码语言:javascript
复制
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就是我们上一篇路由拦截中的onGenerateRoutesettings 参数,因此假设我们需要增加额外的路由参数(例如全局参数),则可以在 onGenerateRoute 方法中重新组装路由参数。 这里有个地方需要注意,因为返回时要携带参数,因此我们需要拦截返回响应事件,这时候整个组件可以使用 WillPopScope 包裹,该方法带有两个参数:

  • child:子组件,即原有的页面组件;
  • onWillPop:返回前拦截处理,返回一个Future<bool>对象,若为 false,则不会返回。若为 true,则返回上一级。这里我们调用了 携带参数的 pop 方法以便将参数回传。实际这里往往做一些其他处理,例如表单没有保存询问是否确认李可,还有广大电商的活动页询问你是“忍痛离开”或是“再看一会”的处理。

路由参数拦截

路由参数可以通过 onGenerateRoute拦截进行额外处理,示例代码如下。需要注意,这里仅仅是示例,由于 settings。arguments 可能为任意类型,因此可能会导致转换失败。实际业务中最好是约定路由参数传递类型,避免参数形式不统一导致异常出现。

代码语言:javascript
复制
static Route onGenerateRoute<T extends Object>(RouteSettings settings) {
  var arguments = settings.arguments as Map<String, dynamic>;
  if (arguments != null) {
    arguments['event'] = '路由拦截增加的参数';
  }
  RouteSettings newSettings =
      settings.copyWith(name: settings.name, arguments: arguments);

  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 实现页面路由。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Navigator 的 push 和 pop方法
  • 代码实现
  • 路由参数拦截
  • 总结
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档