flutter 返回指定界面_Flutter页面路由导航及传参

9858e1c4f17480b6a97155b29f9121ae.png

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

概述

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

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

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

静态路由(即命名路由)

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

import 'package:flutter/material.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {// 常用固定写法,生成Material风格的Appreturn MaterialApp(title: "路由使用",theme: ThemeData(// 默认为亮色主题,可以设置[Brightness.dark]变成黑暗模式brightness: Brightness.light,),home: HomePage(), // 首页面);}
}class HomePage extends StatelessWidget {@overrideWidget build(BuildContext context) {// 通过Scaffold可以方便的生成一个Material风格的页面return Scaffold(// 顶部导航栏appBar: AppBar(title: Text("主页面"),),body: Center(child: RaisedButton(child: Text("我是第一个界面,点击我进入第二个界面"),onPressed: () {print("我是第一个界面,点击我进入第二个界面");},),),);}
}

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

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

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

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

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

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

import 'package:flutter/material.dart';class HomePage extends StatelessWidget {@overrideWidget build(BuildContext context) {// 通过Scaffold可以方便的生成一个Material风格的页面return Scaffold(// 顶部导航栏appBar: AppBar(title: Text("主页面"),),body: Center(child: RaisedButton(child: Text("我是第一个界面,点击我进入第二个界面"),onPressed: () {print("我是第一个界面,点击我进入第二个界面");// 跳转到第二个界面Navigator.pushNamed(context, '/secondPage');},),),);}
}

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

import 'package:flutter/material.dart';class SecondPage extends StatelessWidget {@overrideWidget build(BuildContext context) {// 通过Scaffold可以方便的生成一个Material风格的页面return Scaffold(// 顶部导航栏appBar: AppBar(title: Text("第二个界面"),),body: Center(child: RaisedButton(child: Text("我是第二个界面,点击我进入第二个界面"),onPressed: () {print("我是第二个界面,点击我返回到第一个界面");// 返回上一个界面Navigator.pop(context);},),),);}
}

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

动态路由

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

class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {// 常用固定写法,生成Material风格的Appreturn MaterialApp(title: "路由使用",theme: ThemeData(// 默认为亮色主题,可以设置[Brightness.dark]变成黑暗模式brightness: Brightness.light,),home: HomePage(),);}
}

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

Navigator.push(context,MaterialPageRoute(builder: (context) => SecondPage(),));

动态路由的相互传参

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

class SecondPage extends StatelessWidget {// 定义一个需要变量, 接收传递的参数final String title;// 为title设置一个默认参数,这样的跳转该界面时可以不传值。SecondPage({Key key, this.title = "第二个界面"});@overrideWidget build(BuildContext context) {// 通过Scaffold可以方便的生成一个Material风格的页面return Scaffold(// 顶部导航栏appBar: AppBar(title: Text(title),),body: Center(child: RaisedButton(child: Text("我是第二个界面,点击我进入第二个界面"),onPressed: () {print("我是第二个界面,点击我返回到第一个界面");// 返回上一个界面Navigator.pop(context);},),),);}
}

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

Navigator.push(context,MaterialPageRoute(// 传递title为SecondPage,跳转到第二个界面就会把标题设置为SecondPagebuilder: (context) => SecondPage(title: "SecondPage"),));},

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

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

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

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

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

import 'package:flutter/material.dart';import 'pages/HomePage.dart';
import 'pages/SecondPage.dart';
import 'pages/ThirdPage.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget {// 声明所有的页面final routes = {'/': (context, {arguments}) => HomePage(),'/secondPage': (context, {arguments}) => SecondPage(),'/thirdPage': (context, {arguments}) => ThirdPage(arguments: arguments),};@overrideWidget build(BuildContext context) {// 常用固定写法,生成Material风格的Appreturn MaterialApp(title: "路由使用",theme: ThemeData(// 默认为亮色主题,可以设置[Brightness.dark]变成黑暗模式brightness: Brightness.light,),
//      home: HomePage(),initialRoute: '/', // 默认界面// 当页面跳转时进行参数处理onGenerateRoute: (RouteSettings settings) {// 获取声明的路由页面函数var pageBuilder = routes[settings.name];if (pageBuilder != null) {if (settings.arguments != null) {// 创建路由页面并携带参数return MaterialPageRoute(builder: (context) =>pageBuilder(context, arguments: settings.arguments));} else {return MaterialPageRoute(builder: (context) => pageBuilder(context));}}return MaterialPageRoute(builder: (context) => HomePage());},);}
}

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

import 'package:flutter/material.dart';class SecondPage extends StatelessWidget {// 定义一个需要变量, 接收传递的参数final String title;// 为title设置一个默认参数,这样的跳转该界面时可以不传值。SecondPage({Key key, this.title = "第二个界面"});@overrideWidget build(BuildContext context) {// 通过Scaffold可以方便的生成一个Material风格的页面return Scaffold(// 顶部导航栏appBar: AppBar(title: Text(title),),body: Center(child: RaisedButton(child: Text("我是第二个界面,点击我进入第二个界面"),onPressed: () {print("我是第二个界面,点击我进入第三个界面");// 通过arguments指定参数Navigator.pushNamed(context, "/thirdPage",arguments: {'title': "命令路由传递过来的title"});},),),);}
}

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

import 'package:flutter/material.dart';class ThirdPage extends StatelessWidget {final Map arguments;// 为title设置一个默认参数,这样的跳转该界面时可以不传值。ThirdPage({Key key, this.arguments});@overrideWidget build(BuildContext context) {// 通过Scaffold可以方便的生成一个Material风格的页面return Scaffold(// 顶部导航栏appBar: AppBar(title: Text("${arguments != null ? arguments['title'] : "ThirdPage"}"),),body: Center(child: RaisedButton(child: Text("我是第三个界面,点击我进入第二个界面"),onPressed: () {print("我是第三个界面,点击我返回到第二个界面");// 返回上一个界面Navigator.pop(context, "返回传递数据Page3");},),),);}
}

命名路由传参优化

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

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

import 'package:flutter/material.dart';// 引入页面路径
import '../pages/HomePage.dart';
import '../pages/SecondPage.dart';
import '../pages/ThirdPage.dart';// 声明所有页面
final routes = {'/': (context, {arguments}) => HomePage(),'/secondPage': (context, {arguments}) => SecondPage(),'/thirdPage': (context, {arguments}) => ThirdPage(arguments: arguments),
};// 处理参数传递
// ignore: top_level_function_literal_block
var onGenerateRoute = (RouteSettings settings) {// 获取声明的路由页面函数var pageBuilder = routes[settings.name];if (pageBuilder != null) {if (settings.arguments != null) {// 创建路由页面并携带参数return MaterialPageRoute(builder: (context) =>pageBuilder(context, arguments: settings.arguments));} else {return MaterialPageRoute(builder: (context) => pageBuilder(context));}}return MaterialPageRoute(builder: (context) => HomePage());
};

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

import 'package:flutter/material.dart';
import 'package:hello_flutter/pages/PageConstants.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {// 常用固定写法,生成Material风格的Appreturn MaterialApp(title: "路由使用",theme: ThemeData(// 默认为亮色主题,可以设置[Brightness.dark]变成黑暗模式brightness: Brightness.light,),initialRoute: '/', // 默认界面// 通过PageConstants引入onGenerateRoute: onGenerateRoute,);}
}

这样来看就会清爽很多。

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

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

05f72c33e78d31973655eb87fb98ce16.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/345175.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

正确的工作流程:我应该使用哪个OAuth 2.0流程?

什么是OAuth 2.0 OAuth 2.0是一个已被广泛采用的委托授权框架,已经存在了很多年,并且似乎已经存在。 如果您不熟悉OAuth 2.0的基本概念,可以使用 川崎孝彦写的优秀文章 。 这只是OAuth 2.0各方的简要提醒: 资源所有者–受保护资…

mysql workbench入门_5分钟入门MySQL Workbench

接下来进入下一步,使用Workbench执行sql文件:1.打开Workbench,主页面上点击要connect的连接。2.注意系统偏好设置里,MySQL是running的状态,否则无法执行。创建数据库:点击创建数据库按钮,输入数…

使用Spring Boot和Vue进行有益的开发

“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证。 Vue是一个Web框架,由于它的精简和刻薄,最近引起了很多关注。 …

mysql mydumper_系统运维|Mydumper-MySQL数据库备份工具

Mydumper 是 MySQL 数据库服务器备份工具,它比 MySQL 自带的 mysqldump 快很多。它还有在转储的同时获取远程服务器二进制日志文件的能力。Mydumper 的优势并行能力 (因此有高速度) 和性能 (高效的代码避免了耗费 CPU 处理能力的字符集转换过程)更容易管理输出 (每个…

vue调用手机相机相册_详解Vue调用手机相机和相册以及上传

组件选中{{imgList.length}}张文件,共{{bytesToSize(this.size)}}javaScript代码export default {name: "cameras-and-albums",data(){return{imgList: [],datas: new FormData(),files:0,size:0}},methods:{//调用相册&相机fileClick() {$(#upload_f…

红旗linux mysql_恢复 - 红旗Linux案例精选:Amanda集中备份实例详细讲解_数据库技术_Linux公社-Linux系统门户网站...

五、恢复假定我们需要恢复cp3上一些丢失的数据,首先用amandabackup帐号登录cp2机器,创建/etc/amanda/amanda-client.conf文件,内容如下:## amanda.conf - sample Amanda client configuration file.## This file normally goes in…

linuxpip安装python包_Windows+Linux安装Python包管理工具pip

WindowsLinux安装Python包管理工具pipWindows安装Python包管理工具pippip是一个Python包管理工具,主要是用于安装PyPI上的软件包,可以替代easy_install工具。一、前期准备首先确认windows机器上面是否已经安装好了python。在cmd中输入python --version和…

mysql 深胡_Mysql胡说八道

mysql索引今天看了一些关于MySQL相关的东西,来做一些碎碎念,写这些可能只是觉得自己看东西老爱忘23333.先来看一组MySQL数据,如图我们要查看最后id11的数据,如果我们不加索引的话会怎样呢?他会一条一条的比对&#xff…

java public main_实例分析Java中public static void main(String args[])是什么意思

本文实例讲述了Java中public static void main(String args[])的来龙去脉。分享给大家供大家参考,具体如下:public static void main(String[] args)这绝对不是凭空想出来的,也不是没有道理的死规定,而是java程序执行的需要。jvm在…

java浏览文件夹_一个用java实现简单的文件浏览器

[java]代码库import java.awt.*;import java.awt.event.*;import java.net.URL;import javax.swing.*;//文件浏览器public class HTTPBrowserDemo extends JFrame {private static final long serialVersionUID -5794029080886644211L;JTextField jtfAddress; // 输入文件地址…

java奥运会安排赛程问题_记录奥运-当今五大Java记录框架之间的竞赛

java奥运会安排赛程问题开发人员:Takipi会告诉您何时新代码在生产中中断– Log4J vs SLF4J简单vs Logback vs Java Util日志记录vs LOG4J2 日志记录实际上是每个服务器端应用程序中古老且固有的部分。 这是应用程序以持久且可读的方式输出实时状态的主要方法。 某些…

为什么在子类中不重写超类的实例变量

当我们在父类和子类中创建一个具有相同名称的变量,并尝试使用持有子类对象的父类引用访问它时,我们会得到什么? 为了理解这一点,让我们考虑下面的示例,其中在Parent和Child类中声明一个具有相同名称的变量x 。 class…

cocos lua调用java_【Tech-Lua】Cocos-2dx-Lua调用java的小白教程(三)

上周五下班前,打包成功了。我很高兴,周六去踢场足球,周日去现场看了最后一分钟掉球的恒大,度过了一个愉快的周末。然后,噩梦的周一开始了。我再次打包,打算打包就安装,但结果是失败的。为何&…

github上java项目_GitHub上10,000个最受欢迎的Java项目-以下是他们使用的顶级库

github上java项目随着Java开发人员使用既成熟又高度发展的语言来工作,无论何时编写新代码,我们都将面临一个持续的困境–使用大家都在谈论的热门新技术,或者坚持使用久经考验的库? 由于Java应用程序的很大一部分是商业性质的&…

char java 回文_LeetCode刷题笔记(Java)---第1-18题

题目来自LeetCode文章目录全部章节1-18题19-40题41-60题61-80题81-100题101-120题121-140题1.两数之和2.两数相加3.无重复字符串的最长子串4.寻找两个有序数组的中位数5.最长回文子串6.Z 字形变换7.整数反转8.字符串转换整数 (atoi)9.回文数10.正则表达式匹配11.盛最多水的容器…

使用PostgreSQL使用Spring Boot和JPA构建基本应用

“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证。 每个不平凡的应用程序都需要一种保存和更新数据的方法:可通过HTTP访问的资…

通过示例了解Apache Ignite Baseline拓扑

点燃基准拓扑或BLT表示群集中的一组服务器节点,这些服务器节点将数据持久存储在磁盘上。 其中,N1-2和N5服务器节点是具有本机持久性的Ignite集群的成员,这些集群使数据能够持久存储在磁盘上。 N3-4和N6服务器节点是Ignite群集的成员&#x…

Spring Boot集成测试中@ContextConfiguration和@SpringApplicationConfiguration之间的区别

即使同时使用ContextConfiguration和SpringApplicationConfiguration批注以及SpringJUnit4ClassRunner来指定如何加载Spring应用程序上下文,它们之间也存在细微的差异。 尽管ContextConfiguration在加载应用程序上下文方面表现出色,但没有充分利用Spring…

vert.x_使用vert.x 2.0,RxJava和mongoDB创建simpe RESTful服务

vert.x中断了将近半年后发表了一篇新文章。 在本文中,我们将快速了解如何开始使用vert.x,更有趣的是,如何使用RxJava简化异步系统的编程。 我们将涵盖以下主题: 使用Maven创建一个空的vert.x项目 导入IntelliJ并创建一个简单的H…

如何通过Rultor将Maven工件部署到CloudRepo

在我以前的文章中 ,我描述了如何在Amazon S3中设置私有Maven存储库并通过Rultor进行部署。 如果您熟悉管理Amazon Web Services(AWS), S3和AWS Identity and Access Management(IAM)的话,这是一…