前言

在做 Flutter 开发的时候所有的页面以及页面上的元素都变成了 Widget ,创建一个页面或者视图直接 new 一个新的 widget 就可以,相关的参数我们可以直接通过构造函数直接传递。

我们做 Android 开发的人员都知道 Android 应用程序在进行页面跳转的时候可以利用Intent进行参数传递,那么再开发 Flutter 的时候有类似的方式可以进行参数传递么?答案当然是有。

Flutter中文网 中有一段话,大多数应用程序包含多个页面。例如,我们可能有一个显示产品的页面,然后,用户可以点击产品,跳到该产品的详情页。

在Android中,页面对应的是Activity,在iOS中是ViewController。而在Flutter中,页面只是一个widget!

在Flutter中,我们那么我们可以使用Navigator在页面之间跳转。

所以我们下边讲述 widget 的参数传递,从简单到简便:

widget构造参数传递

route参数传递

上面两种方式进混合(onGenerateRoute)

widget构造参数传递

class Page extends StatelessWidget{Page({this.arguments});final Map arguments;@overrideWidget build(BuildContext context) {return Material(child: Center(child: Text("this page name is ${arguments != null ? arguments['name'] : 'null'}"),),);}
}

上面是一个简单的 Flutter 的视图组件,我们在使用参数 arguments 的时候只需要将其传入到 Page({this.arguments}) 的构造函数中。

void main() => runApp(MyApp());
class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(title: 'Flutter Demo',home: Page(arguments: {"name": 'Flutter Demo Home Page'}),);}
}

这种方式进行的参数传递只能单向往下一个页面传递,不能像Android的 setResult 一样往上一级页面传递数据。

Route

在讲 Route 传参的时候,我们先讲讲 FlutterRoute 相关的知识点。

路由( Route )在移动开发中通常指页面( Page ),这跟 web 开发中单页应用的 Route 概念意义是相同的,RouteAndroid 中通常指一个 Activity ,在 iOS 中指一个 ViewController 。所谓路由管理,就是管理页面之间如何跳转,通常也可被称为导航管理。这和原生开发类似,无论是 Android 还是 iOS ,导航管理都会维护一个路由栈,路由入栈( push )操作对应打开一个新页面,路由出栈( pop)操作对应页面关闭操作,而路由管理主要是指如何来管理路由栈。

MaterialPageRoute

MaterialPageRoute 是我们使用最为广泛的路由类,它继承自 PageRoute 类, PageRoute 类是一个抽象类继承抽象类 ModalRoute,下面我们介绍一下 MaterialPageRoute 构造函数的各个参数的意义:

MaterialPageRoute({@required this.builder,RouteSettings settings,this.maintainState = true,bool fullscreenDialog = false,
}) : assert(builder != null),assert(maintainState != null),assert(fullscreenDialog != null),assert(opaque),super(settings: settings, fullscreenDialog: fullscreenDialog);
  • builder 是一个WidgetBuilder类型的回调函数,它的作用是构建路由页面的具体内容,返回值是一个widget。我们通常要实现此回调,返回新路由的实例。
  • settings 包含路由的配置信息,如路由名称、路由参数、是否初始路由(首页)。
  • maintainState:默认情况下,当入栈一个新路由时,原来的路由仍然会被保存在内存中,如果想在路由没用的时候释放其所占用的所有资源,可以设置maintainState为false。
  • fullscreenDialog表示新的路由页面是否是一个全屏的模态对话框,在iOS中,如果fullscreenDialogtrue,新页面将会从屏幕底部滑入(而不是水平方向)。

如果想自定义路由切换动画,可以自己继承PageRoute来实现,我们将在后面介绍动画时,实现一个自定义的路由Widget。

命名路由

所谓命名路由(Named Route)即给路由起一个名字,然后可以通过路由名字直接打开新的路由。这为路由管理带来了一种直观、简单的方式。和 Android 中的 ARrouter 页面跳转框架所定义的 path 非常的类似。

路由表

要想使用命名路由,我们必须先提供并注册一个路由表(routing table),这样应用程序才知道哪个名称与哪个路由Widget对应。路由表的定义是一个 Map<String, WidgetBuilder> 结构的 Map , key 为路由的名称,是个字符串;value是个builder回调函数,用于生成相应的路由Widget。我们在通过路由名称入栈新路由时,应用会根据路由名称在路由表中找到对应的WidgetBuilder回调函数,然后调用该回调函数生成路由widget并返回。

我们在创建 MaterialApp 的时候就有一个 routes 构造参数:

const MaterialApp({Key key,this.navigatorKey,this.home,this.routes = const <String, WidgetBuilder>{},this.initialRoute,this.onGenerateRoute,this.onUnknownRoute,this.navigatorObservers = const <NavigatorObserver>[],/***********/
})

Navigator

Navigator是一个路由管理的widget,它通过一个栈来管理一个路由widget集合。通常当前屏幕显示的页面就是栈顶的路由。Navigator提供了一系列方法来管理路由栈,我们主要使用 pushpop 连个操作进行页面的入栈和出栈。

push

将给定的路由入栈(即打开新的页面),返回值是一个Future对象,用以接收新路由出栈(即关闭)时的返回数据。

push 我们主要使用两个方法一个是直接 push 一个路由,另外一个是 pushNamed 一个命名路由地址(PS:要想使用命名路由必须提供并注册一个路由表,这后面会讲到)。

push方法源码

下边是 Navigator.push 的源码,入参的 Route 对象中有一个 RouteSettings 成员变量,我们可以在构造 Route 对象的时候将需要传递的参数放在 RouteSettings 中。

@optionalTypeArgs
static Future<T> push<T extends Object>(BuildContext context, Route<T> route) {return Navigator.of(context).push(route);
}

push方法使用

我们可以将参数放在 SecondScreen 的构造函数中,也可以放在构造的 MaterialPageRouteRouteSettings 中。

Navigator.push(context,new MaterialPageRoute(builder: (context) => new SecondScreen()),
).then((data){//接受返回的参数print(data.toString());
};

pushNamed方法源码

第二种方式最终的实现也是调用的 push 方法,这中方法直接暴露了参数 Object arguments

@optionalTypeArgs
static Future<T> pushNamed<T extends Object>(BuildContext context,String routeName, {Object arguments,}) {return Navigator.of(context).pushNamed<T>(routeName, arguments: arguments);
}
@optionalTypeArgs
Future<T> pushNamed<T extends Object>(String routeName, {Object arguments,
}) {return push<T>(_routeNamed<T>(routeName, arguments: arguments));
}

pushNamed方法使用

使用前提是 /route1 已经被注册到路由表中:

Navigator.of(context).pushNamed('/route1',arguments: {"name": 'hello'}).then((data){//接受返回的参数print(data.toString());};

pop

将栈顶路由出栈,入参为一个 object 类型的对象为当前页面关闭时返回给上一个页面的数据。

@optionalTypeArgs
static bool pop<T extends Object>(BuildContext context, [ T result ]) {return Navigator.of(context).pop<T>(result);
}

使用非常简单:

Navigator.of(context).pop("ok~!");

页面参数的传输、获取以及结果返回

参数传输

Navigator.of(context).pushNamed('/route1', arguments: {"name": 'hello'});

参数获取

class Page extends StatelessWidget{String name;@overrideWidget build(BuildContext context) {dynamic obj = ModalRoute.of(context).settings.arguments;if (obj != null && isNotEmpty(obj["name"])) {name = obj["name"];}return Material(child: Center(child: Text("this page name is ${name}"),),);}
}

参数返回

//页面返回参数
Navigator.of(context).pop("ok~!");
//上一个页面接收参数
Navigator.of(context).pushNamed('/route1',arguments: {"name": 'hello'}).then((data){//接受返回的参数print(data.toString());};

onGenerateRoute构建路由

在说 onGenerateRoute 构建路由之前,我们得先了解他。前面 MaterialApp 的的构造函数中我们看到过它出现, MaterialApp 有一个参数类型为 Function 类型的 onGenerateRoute

void main() => runApp(MyApp());
Map<String, WidgetBuilder> routers = {'/route1': (context, {arguments}) => Page(arguments: arguments)}
class MyApp extends StatelessWidget {// This widget is the root of your application.@overrideWidget build(BuildContext context) {return MaterialApp(title: 'Flutter Demo',// 处理Named页面跳转 传递参数onGenerateRoute: (RouteSettings settings) {// 统一处理final String name = settings.name;final Function pageContentBuilder = routers[name];if (pageContentBuilder != null) {final Route route =MaterialPageRoute(builder: (context) {//将RouteSettings中的arguments参数取出来,通过构造函数传入return pageContentBuilder(context, arguments: settings.arguments);},settings: settings,);return route;}},theme: ThemeData(primarySwatch: Colors.blue,),home: MyHomePage(name: 'Flutter Demo Home Page'),//routes优先执行,所以必须注释掉,否则onGenerateRoute方法不会调用//routes: routers,);}
}
class Page extends StatelessWidget{Page({this.arguments});final Map arguments;@overrideWidget build(BuildContext context) {return Material(child: Center(child: Text("this page name is ${arguments != null ? arguments['name'] : 'null'}"),),);}
}
  • 这种方式统一处理了页面的 arguments 参数,所以必须保证 Map<String, WidgetBuilder> routers 当中注册的所有 Widget 的构造函数中都有一个 Map 类型并且名为 arguments 的参数。
  • 这种方法同时也传递了 RouteSettings ,所以在下一个页面我们也可以通过 ModalRoute.of(context).settings.arguments 方式获取参数。
  • 这种方式可以自定义 PageRoute 的类型,比如自带 IOS 侧滑返回效果的 CupertinoPageRoute 等。之前通过在 WidgetsApp 注册routes 的方式默认生成的 PageRoute 类型为 MaterialPageRoute

源码分析传送门:Flutter路由管理和页面参数的传递(源码分析)

文章到这里就全部讲述完啦,若有其他需要交流的可以留言哦

想阅读作者的更多文章,可以查看我 个人博客 和公共号:

Flutter路由管理和页面参数的传递(获取返回)相关推荐

  1. Flutter路由管理和页面参数的传递(源码分析)

    前言 上一篇 Flutter路由管理和页面参数的传递(获取&返回) 文章中我们讲述了这么用代码实现 Flutter 中页面参数的传递,这一篇我们用源码分析一下 Navigator 为什么可以进 ...

  2. Flutter系列-flutter路由管理

    Flutter路由管理 初识路由概念 一.路由管理 1.1.Route 1.2.MaterialPageRoute 1.3.Navigator 1.4.路由传值 1.5 命名路由 1.6.命名路由参数 ...

  3. Flutter路由管理和接收页面的返回值

    Flutter使用Navigator进行路由管理. 跳转页面 使用Navigator的push方法进行跳转.可以看到总共有6个push方法 1.push(route) 通过路由跳转 通过路由进行跳转 ...

  4. Bolt 的 Flutter 路由管理实践(页面解耦,流程控制、功能拓展等)

    在各大移动开发框架(Android.iOS.Flutter.React Native-)中,路由管理始终是 UI 架构最具热议的话题之一. 一大原因就是应用程序的页面会 不可避免的多,我们可以使用 B ...

  5. Flutter路由管理代码这么长长长长长,阿里工程师怎么高效解决?(实用)

    背景: 在flutter的业务开发过程中,flutter侧会逐渐丰富自己的路由管理.一个轻量的路由管理本质上是页面标识(或页面路径)与页面实例的映射.本文基于dart注解提供了一个轻量路由管理方案.  ...

  6. 【Vue3从零开始-实战】S14:详情页回退事件及路由参数的传递获取数据

    前言 实战已经开始了!上一篇已经将详情页的店铺信息展示出来了,但是顶部还有一个搜索框和返回按钮,而且详情页的店铺数据是在页面中固定写死的,所以本章节会将顶部搜索栏进行布局,并且通过返回按钮可以回到首页 ...

  7. 使用VBA调用jar传递参数,并获取返回值

    目录 ■VBA代码 ■Java代码 ■运行效果 Excel Log效果 (通过VBA调用jar后,运行,生成的Log) ■课题 ■课题原因(直接原因) ●log4j的配置 ■课题验证 ■课题解决(其他 ...

  8. 结构体作为参数的传递和返回

    结构是多个变量的集合,可以作为函数的参数或者返回值, 按值传递是参数传递的一种方式,就是把实参赋给形参,相当于复制了实参,形参的修改不会影响实参的变化, <span style="fo ...

  9. 3-4 页面路由参数的传递

    我们希望,点击每一个List 进入详情页的时候,把它的id 也传递给详情页,这样详情页就可以根据id 返回对象的值了. 这儿,我们有两种方式\. 首先我们来看看动态路由: 打开 src/pages/h ...

最新文章

  1. 淘淘经受了一次考验...
  2. 7 Papers Radios | 机器人「造孩子」;谷歌裸眼3D全息视频聊天技术公开
  3. 物联网管理软件的设计
  4. 理解Node.js的异步非阻塞I/O模型
  5. SAP Spartacus的单页面应用特性
  6. 三层架构+ajax分页实例,ASP.NET存储过程实现分页效果(三层架构)
  7. 一:ActiveMQ知识整理
  8. c 语言 strcmpy的实现
  9. Android获取SharedPreferences失败,且App无法启动
  10. postman 返回json乱码_post json 中文编码问题
  11. android游戏开发学习笔记一(学习书籍 Android游戏编程之从零开始)
  12. MATLAB music分解信号,MUSIC算法信号频率问题求解
  13. 微信小程序地图组件利用腾讯地图生成热力图
  14. 向量的点击、叉积、混合积(Matlab)
  15. 致加西亚的信 名言佳句
  16. Windows Defender无法关闭的红叉
  17. SDH(标准DH)和MDH(改进DH)
  18. Arcgis连接sql server发布地图服务详解
  19. 软件工程之项目团队分工
  20. 贾俊平《统计学》第七章知识点总结及课后习题答案

热门文章

  1. 如何做好PPT——画图篇
  2. IT信息考证人,证书记得要延续 ITSS CISAW CISP PMP CISSP 证书延续 有效期
  3. 注册表去掉多余的安全删除硬件图标
  4. bigworld源码分析(1)—— 研究bigworld的意义和目标
  5. MySQL轻快入门2021.3.18(事务)
  6. 图片降噪软件哪个好?不如试试Topaz DeNoise AI
  7. 四川锦城学院计算机专业好不,四川大学锦城学院计算机专业如何?
  8. 美国CN2服务器推荐:RAKsmart电信Cn2 GIA直连服务器
  9. mermaid与flowchart.js绘制流程图分支结构试验
  10. Real-Time Rendering Chapter 1~6 读书笔记