当前位置:   article > 正文

Flutter页面路由导航及传参_flutter 路由传参

flutter 路由传参

转载请注明出处: https://learnandfish.com/

概述

每个应用都有很多个页面,在flutter中同样也有很多页面,被称之为路由(Router),页面之间的跳转通过导航器(Navigator)进行管理。
其中 Navigator.push 和 Navigator.pop 是最简单的跳转到新页面和返回到上一级界面的方式。

路由分为静态路由(即命名路由)和动态路由。页面之间跳转时往往需要传递参数,这称之为路由传值。下面我们会一一带领大家学习。

通过本篇文章的学习我们的目标是熟练掌握路由及传值,以后进行应用开发时对页面跳转方面不再疑惑。

静态路由(即命名路由)

flutter中万物皆widget,我们的页面(route)也是widget的子类,所以我们定义一个界面也是通过继承widget实现。
前面的博客我们已经定义过界面了,比如计数器实例,就是一个简单的页面,也就是一个路由。下面我们来详细实现一个界面。
首先我需要一个入口函数,这个相信大家已经很熟悉了,就是在main方法中调用runApp函数进入应用,我们就不做详细介绍了,直接给出代码。

  1. import 'package:flutter/material.dart';
  2. void main() => runApp(MyApp());
  3. class MyApp extends StatelessWidget {
  4.   @override
  5.   Widget build(BuildContext context) {
  6.     // 常用固定写法,生成Material风格的App
  7.     return MaterialApp(
  8.       title"路由使用",
  9.       themeThemeData(
  10.         // 默认为亮色主题,可以设置[Brightness.dark]变成黑暗模式
  11.         brightness: Brightness.light,
  12.       ),
  13.       homeHomePage(), // 首页面
  14.     );
  15.   }
  16. }
  17. class HomePage extends StatelessWidget {
  18.   @override
  19.   Widget build(BuildContext context) {
  20.     // 通过Scaffold可以方便的生成一个Material风格的页面
  21.     return Scaffold(
  22.       // 顶部导航栏
  23.       appBarAppBar(
  24.         titleText("主页面"),
  25.       ),
  26.       bodyCenter(
  27.         childRaisedButton(
  28.           childText("我是第一个界面,点击我进入第二个界面"),
  29.           onPressed: () {
  30.             print("我是第一个界面,点击我进入第二个界面");
  31.           },
  32.         ),
  33.       ),
  34.     );
  35.   }
  36. }

上面的代码是我们最常规的包含一个主页面的应用。后续我们写应用时候的基本框架也是在此基础上进行扩展。
现在我们的想法是点击这个页面上的按钮跳转的第二个界面,首先我们需要构造第二个界面。构造第二个界面其实和我们构造第一个
界面HomePage一样,继承widget重写自己想要的样式即可。实现了页面就要开始跳转逻辑。

静态路由即命名路由,在通过Navigator进行跳转之前,需要在MaterialApp组件内显式声明路由的名称,一旦声明,路由的跳转
方式就固定了,所以称之为静态路由,有唯一的名称所以也称之为命令路由。显式声明路由通过在MaterialApp内的routes属性进行定义。

如果我们有很多个页面和很多个其他类型的组件都放在lib下,对于后期维护简直是一大折磨,所以分包是大多数平台的常规操作,
就是对有同一种特性的东西放置在同一个包下,比如页面类的组件都放在pages包,工具类的组件放在utils包下等。
接下来我们就新建一个pages包,把第二个界面SecondPage放进去,把第一个界面HomePage也提取出来放到这个包下。

我们分为一下三步进行静态路由的跳转:

  • 首先在lib目录右键新建pages包,接着在pages包下新建SecondPage.dart文件,然后把HomePage提取到pages下,成为单独的类。
  • 在RouteDemo类中的MaterialApp内声明routes属性,为了显示声明路由的名称。
  • 使用Navigator进行页面的跳转和返回。
  1. import 'package:flutter/material.dart';
  2. // 引入页面路径
  3. import 'pages/HomePage.dart';
  4. import 'pages/SecondPage.dart';
  5. void main() => runApp(MyApp());
  6. class MyApp extends StatelessWidget {
  7.   @override
  8.   Widget build(BuildContext context) {
  9.     // 常用固定写法,生成Material风格的App
  10.     return MaterialApp(
  11.       title: "路由使用",
  12.       theme: ThemeData(
  13.         // 默认为亮色主题,可以设置[Brightness.dark]变成黑暗模式
  14.         brightness: Brightness.light,
  15.       ),
  16.       // 默认加载的页面
  17.       initialRoute: '/'// 首页面
  18.       // 显式声明界面列表
  19.       routes: {
  20.         '/': (context) => HomePage(),
  21.         '/secondPage': (context) => SecondPage(),
  22.       },
  23.     );
  24.   }
  25. }

首页面单独提取出来之后的代码如下。

  1. import 'package:flutter/material.dart';
  2. class HomePage extends StatelessWidget {
  3.   @override
  4.   Widget build(BuildContext context) {
  5.     // 通过Scaffold可以方便的生成一个Material风格的页面
  6.     return Scaffold(
  7.       // 顶部导航栏
  8.       appBarAppBar(
  9.         titleText("主页面"),
  10.       ),
  11.       bodyCenter(
  12.         childRaisedButton(
  13.           childText("我是第一个界面,点击我进入第二个界面"),
  14.           onPressed: () {
  15.             print("我是第一个界面,点击我进入第二个界面");
  16.             // 跳转到第二个界面
  17.             Navigator.pushNamed(context, '/secondPage');
  18.           },
  19.         ),
  20.       ),
  21.     );
  22.   }
  23. }

第二个页面提取之后的代码。

  1. import 'package:flutter/material.dart';
  2. class SecondPage extends StatelessWidget {
  3.   @override
  4.   Widget build(BuildContext context) {
  5.     // 通过Scaffold可以方便的生成一个Material风格的页面
  6.     return Scaffold(
  7.       // 顶部导航栏
  8.       appBarAppBar(
  9.         titleText("第二个界面"),
  10.       ),
  11.       bodyCenter(
  12.         childRaisedButton(
  13.           childText("我是第二个界面,点击我进入第二个界面"),
  14.           onPressed: () {
  15.             print("我是第二个界面,点击我返回到第一个界面");
  16.             // 返回上一个界面
  17.             Navigator.pop(context);
  18.           },
  19.         ),
  20.       ),
  21.     );
  22.   }
  23. }

对于命名路由的跳转,通过Navigator.pushNamed方法调用,通过Navigator.pop方法返回上一级界面。

动态路由

动态路由不需要显示声明,直接通过代码实现。

  1. class MyApp extends StatelessWidget {
  2.   @override
  3.   Widget build(BuildContext context) {
  4.     // 常用固定写法,生成Material风格的App
  5.     return MaterialApp(
  6.       title"路由使用",
  7.       themeThemeData(
  8.         // 默认为亮色主题,可以设置[Brightness.dark]变成黑暗模式
  9.         brightness: Brightness.light,
  10.       ),
  11.       homeHomePage(),
  12.     );
  13.   }
  14. }

在HomePage界面通过调用Navigator.push方法实现跳转。第二个页面的返回逻辑不变。

  1. Navigator.push(
  2.                 context,
  3.                 MaterialPageRoute(
  4.                   builder: (context) => SecondPage(),
  5.                 ));

动态路由的相互传参

有时候我们不仅需要跳转到对应界面,还需要传递一些参数给下一个界面,同时下一个界面返回时,把某些参数再次传递给该界面。
我们修改SecondPage组件的构造方法,为了接收需要传递的参数。这时候我们第二个页面结构如下:

  1. class SecondPage extends StatelessWidget {
  2.   // 定义一个需要变量, 接收传递的参数
  3.   final String title;
  4.   // 为title设置一个默认参数,这样的跳转该界面时可以不传值。
  5.   SecondPage({Key key, this.title = "第二个界面"});
  6.   @override
  7.   Widget build(BuildContext context) {
  8.     // 通过Scaffold可以方便的生成一个Material风格的页面
  9.     return Scaffold(
  10.       // 顶部导航栏
  11.       appBar: AppBar(
  12.         title: Text(title),
  13.       ),
  14.       body: Center(
  15.         child: RaisedButton(
  16.           child: Text("我是第二个界面,点击我进入第二个界面"),
  17.           onPressed: () {
  18.             print("我是第二个界面,点击我返回到第一个界面");
  19.             // 返回上一个界面
  20.             Navigator.pop(context);
  21.           },
  22.         ),
  23.       ),
  24.     );
  25.   }
  26. }

第一个界面跳转的地方代码是这样的。

  1. Navigator.push(
  2.                 context,
  3.                 MaterialPageRoute(
  4.                   // 传递title为SecondPage,跳转到第二个界面就会把标题设置为SecondPage
  5.                   builder: (context) => SecondPage(title"SecondPage"),
  6.                 ));
  7.           },

说完了从第一个页面往第二个页面传递了参数,如果第二个页面返回时传递一句话,然后第一个页面接收到这句话然后打印出来,
代码修改如下:

  1. // HomePage页面代码
  2. Navigator.push(
  3.                 context,
  4.                 MaterialPageRoute(
  5.                   // 传递title为SecondPage,跳转到第二个界面就会把标题设置为SecondPage
  6.                   builder: (context) => SecondPage(title: "SecondPage"),
  7.                   // 调用then等待接收返回数据
  8.                 )).then((value=> print(value));
  9. // SecondPage页面代码
  10.  Navigator.pop(context, "返回传递数据");

静态路由(即命名路由)的相互传参

讲完了动态路由及动态路由传参之后,我们来讲一下静态路由传参,参数的传递方式是flutter为我们定义好的,我们只需要把固定
代码拷贝回来,稍微修改即可。为了更具有普遍性,我们再定义一个页面ThirdPage。

在我们显示声明了routes之后,还需要在MaterialApp组件内添加onGenerateRoute属性内容进行参数传递的处理。
完整代码如下:

  1. import 'package:flutter/material.dart';
  2. import 'pages/HomePage.dart';
  3. import 'pages/SecondPage.dart';
  4. import 'pages/ThirdPage.dart';
  5. void main() => runApp(MyApp());
  6. class MyApp extends StatelessWidget {
  7.   // 声明所有的页面
  8.   final routes = {
  9.     '/'(context, {arguments}) => HomePage(),
  10.     '/secondPage'(context, {arguments}) => SecondPage(),
  11.     '/thirdPage'(context, {arguments}) => ThirdPage(argumentsarguments),
  12.   };
  13.   @override
  14.   Widget build(BuildContext context) {
  15.     // 常用固定写法,生成Material风格的App
  16.     return MaterialApp(
  17.       title"路由使用",
  18.       themeThemeData(
  19.         // 默认为亮色主题,可以设置[Brightness.dark]变成黑暗模式
  20.         brightnessBrightness.light,
  21.       ),
  22. //      home: HomePage(),
  23.       initialRoute'/'// 默认界面
  24.       // 当页面跳转时进行参数处理
  25.       onGenerateRoute: (RouteSettings settings) {
  26.         // 获取声明的路由页面函数
  27.         var pageBuilder = routes[settings.name];
  28.         if (pageBuilder != null) {
  29.           if (settings.arguments != null) {
  30.             // 创建路由页面并携带参数
  31.             return MaterialPageRoute(
  32.                 builder(context) =>
  33.                     pageBuilder(context, arguments: settings.arguments));
  34.           } else {
  35.             return MaterialPageRoute(
  36.                 builder(context) => pageBuilder(context));
  37.           }
  38.         }
  39.         return MaterialPageRoute(builder(context) => HomePage());
  40.       },
  41.     );
  42.   }
  43. }

第二个页面传递参数时使用Navigator.pushNamed方法,具体代码如下:

  1. import 'package:flutter/material.dart';
  2. class SecondPage extends StatelessWidget {
  3.   // 定义一个需要变量, 接收传递的参数
  4.   final String title;
  5.   // 为title设置一个默认参数,这样的跳转该界面时可以不传值。
  6.   SecondPage({Key key, this.title = "第二个界面"});
  7.   @override
  8.   Widget build(BuildContext context) {
  9.     // 通过Scaffold可以方便的生成一个Material风格的页面
  10.     return Scaffold(
  11.       // 顶部导航栏
  12.       appBar: AppBar(
  13.         title: Text(title),
  14.       ),
  15.       body: Center(
  16.         child: RaisedButton(
  17.           child: Text("我是第二个界面,点击我进入第二个界面"),
  18.           onPressed: () {
  19.             print("我是第二个界面,点击我进入第三个界面");
  20.             // 通过arguments指定参数
  21.             Navigator.pushNamed(context, "/thirdPage",
  22.                 arguments: {'title'"命令路由传递过来的title"});
  23.           },
  24.         ),
  25.       ),
  26.     );
  27.   }
  28. }

第三个页面获取参数,完整代码如下:

  1. import 'package:flutter/material.dart';
  2. class ThirdPage extends StatelessWidget {
  3.   final Map arguments;
  4.   // 为title设置一个默认参数,这样的跳转该界面时可以不传值。
  5.   ThirdPage({Key key, this.arguments});
  6.   @override
  7.   Widget build(BuildContext context) {
  8.     // 通过Scaffold可以方便的生成一个Material风格的页面
  9.     return Scaffold(
  10.       // 顶部导航栏
  11.       appBar: AppBar(
  12.         title: Text("${arguments != null ? arguments['title'] : "ThirdPage"}"),
  13.       ),
  14.       body: Center(
  15.         child: RaisedButton(
  16.           child: Text("我是第三个界面,点击我进入第二个界面"),
  17.           onPressed: () {
  18.             print("我是第三个界面,点击我返回到第二个界面");
  19.             // 返回上一个界面
  20.             Navigator.pop(context, "返回传递数据Page3");
  21.           },
  22.         ),
  23.       ),
  24.     );
  25.   }
  26. }

命名路由传参优化

上面我们已经实现了参数的传递,但是routes页面列表和onGenerateRoute比较固定,我们能够把这两个单独提取出来成为
一个单独的类,这样后期再创建页面或者维护的时候只需要修改这一个类就行了。

我们新建一个PageConstants类,进行提取,修改后的代码如下:

  1. import 'package:flutter/material.dart';
  2. // 引入页面路径
  3. import '../pages/HomePage.dart';
  4. import '../pages/SecondPage.dart';
  5. import '../pages/ThirdPage.dart';
  6. // 声明所有页面
  7. final routes = {
  8.   '/': (context, {arguments}) => HomePage(),
  9.   '/secondPage': (context, {arguments}) => SecondPage(),
  10.   '/thirdPage': (context, {arguments}) => ThirdPage(arguments: arguments),
  11. };
  12. // 处理参数传递
  13. // ignore: top_level_function_literal_block
  14. var onGenerateRoute = (RouteSettings settings) {
  15.   // 获取声明的路由页面函数
  16.   var pageBuilder = routes[settings.name];
  17.   if (pageBuilder != null) {
  18.     if (settings.arguments != null) {
  19.       // 创建路由页面并携带参数
  20.       return MaterialPageRoute(
  21.           builder: (context) =>
  22.               pageBuilder(context, arguments: settings.arguments));
  23.     } else {
  24.       return MaterialPageRoute(
  25.           builder: (context) => pageBuilder(context));
  26.     }
  27.   }
  28.   return MaterialPageRoute(builder: (context) => HomePage());
  29. };

这时候我们只需要简单修改MyApp组件即可:

  1. import 'package:flutter/material.dart';
  2. import 'package:hello_flutter/pages/PageConstants.dart';
  3. void main() => runApp(MyApp());
  4. class MyApp extends StatelessWidget {
  5.   @override
  6.   Widget build(BuildContext context) {
  7.     // 常用固定写法,生成Material风格的App
  8.     return MaterialApp(
  9.       title: "路由使用",
  10.       theme: ThemeData(
  11.         // 默认为亮色主题,可以设置[Brightness.dark]变成黑暗模式
  12.         brightness: Brightness.light,
  13.       ),
  14.       initialRoute: '/'// 默认界面
  15.       // 通过PageConstants引入
  16.       onGenerateRoute: onGenerateRoute,
  17.     );
  18.   }
  19. }

这样来看就会清爽很多。

篇幅所限,这次的内容就先讲到这里,下篇文章继续讲往后的内容,应该会单独讲一讲实现仿闲鱼底部tab页面切换和仿头条多tab页切换。

为了第一时间获取最新文章,请关注公众号 -- 程序员指北,每一个关注都能让作者多搬一块砖。

                             

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/995693
推荐阅读
相关标签
  

闽ICP备14008679号