Flutter第十三弹 路由和导航

目标:

1.Flutter怎么创建路由?

2.怎么实现路由跳转?页面返回?

一、路由

1.1 什么是路由?

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

路由通常通过维护一个路由表,建立页面导航表。

1.2 路由导航

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {// 需要返回MaterialApp,MaterialApp内部已经实现了Navigatorreturn MaterialApp(home: Scaffold(appBar: AppBar(title: Text("首页")),body: Column(children: [Text("这是第一页"),RaisedButton(onPressed: () {/// 实现点击事件/// TODO: 导航跳转第二页debugPrint("导航跳转第二页");// 定义导航路由(导航到SecondRoute)Navigator.push(context, MaterialPageRoute(builder: (_) {return SecondRoute();}));},// 按钮显示内容child: Text("进入第二页"),)],),),);}
}class SecondRoute extends StatelessWidget {@overrideWidget build(BuildContext context) {// 返回页面为脚手架开始,公用MaterialAppreturn Scaffold(appBar: AppBar(title: Text("第二页"),),body: Column(children: [Text("这是第二页"),RaisedButton(onPressed: () {/// 实现点击事件Navigator.pop(context);},// 按钮显示内容(返回上一页)child: Text("返回"),)],),);}
}

新建两个页面,第一个页面点击按钮,跳转第二个页面。

报错信息如下。

1.2.1 导航问题分析

 导航操作请求使用了不包含Navigator的上下文context

`Navigator`实际上也是一个Widget,这个异常出现在`Navigator.of(context)`路由器的获取上,而这句代码会**从当前的context的父级一层层向上去查找一个`Navigator`**,我们当前传递的context就是MyApp,它的父级是root——UI根节点。`Navigator`这个widget的并不是由root创建的,因此在root下一级的上下文中无法获得`Navigator`。

在之前所有的路由案例中,我们的上下文是MainRoute,它的父级是MaterialApp。MaterialApp内部就会创建一个Navigator

MaterialApp->\_MaterialAppState->WidgetsApp->\_WidgetsAppState

所以问题就在于,`Navigator`需要通过MaterialApp或者它孩子的上下文。

1.2.2  导航解决方案

Navigator必须在MaterialApp下一级,这样获取的Element的上下文才是MaterialApp的上下文。

 解决方案一:MaterialApp下body提取一级MainRoute

新的层级结构

root

 |---MaterialApp-->Navigator

           |--------->MainRoute

是指MainRoute的层级在MaterialApp下一级。

这样,MainRoute就能够访问父Element的Navigator。

跳转第二页成功。

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {// 需要返回MaterialApp,MaterialApp内部已经实现了Navigatorreturn MaterialApp(home: MainRoute(),);}
}class MainRoute extends StatelessWidget{@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("首页")),body: Column(children: [Text("这是第一页"),RaisedButton(onPressed: () {/// 实现点击事件/// TODO: 导航跳转第二页debugPrint("导航跳转第二页");// 定义导航路由(导航到SecondRoute)/// 因为context是MyApp的BuildContext,MyApp不包含Navigator,因此报错/// Navigator必须在MaterialApp下一级///Navigator.push(context, MaterialPageRoute(builder: (context) {return SecondRoute();}));// Navigator.push(MaterialPageRoute(//// ))},// 按钮显示内容child: Text("进入第二页"),)],),);}
}class SecondRoute extends StatelessWidget {@overrideWidget build(BuildContext context) {// 返回页面为脚手架开始,公用MaterialAppreturn Scaffold(appBar: AppBar(title: Text("第二页"),),body: Column(children: [Text("这是第二页"),RaisedButton(onPressed: () {/// 实现点击事件Navigator.pop(context);},// 按钮显示内容(返回上一页)child: Text("返回"),)],),);}
}
解决方案二:MaterialApp.Builder构建子树

MaterialApp下的子控件Builder,通过Builder构建的子树,上下文是Builder,因此一定在MaterialApp下面。

1.3 命名路由

给页面增加路由名字,建立路由表。

 1.3.1 注册路由表

MaterialApp.routes注册路由表。

路由表定义路由名称和对应的路由导航页面。

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';void main() {runApp(MyApp());
}class RouteTable {static String ROUTE_MAIN = "/main";static String ROUTE_SECOND = "/second";
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {// 需要返回MaterialApp,MaterialApp内部已经实现了Navigatorreturn MaterialApp(home: MainRoute(),routes: {RouteTable.ROUTE_MAIN: (_) {return new MainRoute();},RouteTable.ROUTE_SECOND: (_) {return new SecondRoute();}},);}
}class MainRoute extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("首页")),body: Column(children: [Text("这是第一页"),RaisedButton(onPressed: () {/// 实现点击事件/// TODO: 导航跳转第二页debugPrint("命名路由导航跳转第二页");// 定义导航路由(导航到SecondRoute)/// 因为context是MyApp的BuildContext,MyApp不包含Navigator,因此报错/// Navigator必须在MaterialApp下一级/// 命令路由跳转的时候采用路由表Navigator.pushNamed(context, RouteTable.ROUTE_SECOND);// Navigator.push(MaterialPageRoute(//// ))},// 按钮显示内容child: Text("进入第二页"),)],),);}
}class SecondRoute extends StatelessWidget {@overrideWidget build(BuildContext context) {// 返回页面为脚手架开始,公用MaterialAppreturn Scaffold(appBar: AppBar(title: Text("第二页"),),body: Column(children: [Text("这是第二页"),RaisedButton(onPressed: () {/// 实现点击事件Navigator.pop(context);},// 按钮显示内容(返回上一页)child: Text("返回"),)],),);}
}

1.3.2 路由导航

路由导航通过命名路由进行导航。

Navigator.pushNamed(context, RouteTable.ROUTE_SECOND);

二、页面参数返回

在项目中,跳转一个新页面以后,处理完成,回到第一个页面,可能需要处理返回来的参数。

这就需要涉及到页面参数返回和接收。

2.1 返回参数保存

Navigator.pop携带返回结果

class Result {String name;int score;Result(this.name, this.score);@overrideString toString() {return 'Result{name: $name, score: $score}';}
}class SecondRoute extends StatelessWidget {@overrideWidget build(BuildContext context) {// 返回页面为脚手架开始,公用MaterialAppreturn Scaffold(appBar: AppBar(title: Text("第二页"),),body: Column(children: [Text("这是第二页"),RaisedButton(onPressed: () {/// 实现点击事件/// 返回上一个页面,携带处理结果。例如当前处理结果是一个对象Navigator.pop(context, new Result("超新星", 100));},// 按钮显示内容(返回上一页)child: Text("返回"),)],),);}
}

Navigator.pop携带一个结果返回上一页。

2.2 接收返回结果

第一页需要接收页面返回结果

2.2.1 onPress方法修改为异步方法 async

对应异步接收处理的方法,声明为async。

2.2.2 Navigator.push的异步返回结果接收

class MainRoute extends StatelessWidget{@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("首页")),body: Column(children: [Text("这是第一页"),RaisedButton(/// 1) 修改为异步任务,等待页面返回onPressed: () async {/// 实现点击事件debugPrint("导航跳转第二页");// 定义导航路由(导航到SecondRoute)/// 因为context是MyApp的BuildContext,MyApp不包含Navigator,因此报错/// Navigator必须在MaterialApp下一级/// 2) 通过await等待返回结果///Result result =  await Navigator.push(context, MaterialPageRoute(builder: (context) {return SecondRoute();}));debugPrint("接收结果 result = " + result.toString());},// 按钮显示内容child: Text("进入第二页"),)],),);}
}

返回结果数据,是泛型数据,顶级类Object的子类。因此几乎所有类型都可以。 

三、定制页面切换动画

Material库中提供了MaterialPageRoute,它在Android上会上下滑动切换。如果想自定义路由切换动画,可以使用PageRouteBuilder。

3.1 页面水平切换

导航到下一个页面的时候,增加水平滑动效果。

SlideTransition是水平滑动动画,position定义平移的动画效果。

我们采用Tween补间动画效果。 

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';void main() {runApp(MyApp());
}class RouteTable {/// 首页默认使用 / 定义这个路由的话,MaterialApp的home不需要重复定义static String ROUTE_MAIN = "/";static String ROUTE_SECOND = "/second";
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {// 需要返回MaterialApp,MaterialApp内部已经实现了Navigatorreturn MaterialApp(home: MainRoute(),// routes: {//   RouteTable.ROUTE_MAIN: (_) {//     return new MainRoute();//   },//   RouteTable.ROUTE_SECOND: (_) {//     return new SecondRoute();//   }// },);}
}class MainRoute extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("首页")),body: Column(children: [RaisedButton(onPressed: () {/// 实现点击事件debugPrint("命名路由导航跳转第二页");// 定义导航路由(导航到SecondRoute)/// 因为context是MyApp的BuildContext,MyApp不包含Navigator,因此报错/// Navigator必须在MaterialApp下一级/// push 的时候,增加路由跳转动画效果Navigator.push(context, PageRouteBuilder(pageBuilder:(BuildContext context, Animation<double> animation,Animation<double> secondaryAnimation) {return SlideTransition(position: Tween<Offset>(begin: const Offset(1.0, 0.0),end: const Offset(0.0, 0.0),).animate(animation),///  child导航的第二个页面child: SecondRoute(),);}));},// 按钮显示内容child: Text("进入第二页"),)],),);}
}class SecondRoute extends StatelessWidget {@overrideWidget build(BuildContext context) {// 返回页面为脚手架开始,公用MaterialAppreturn Scaffold(appBar: AppBar(title: Text("第二页"),),body: Column(children: [Text("这是第二页"),RaisedButton(onPressed: () {/// 实现点击事件Navigator.pop(context);},// 按钮显示内容(返回上一页)child: Text("返回"),)],),);}
}

需要注意切换到第二个页面,child为SecondRoute

3.2 渐变+滑动动画

在滑动动画外层嵌套一层渐变动画。

child对应滑动动画。

class MainRoute extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("首页")),body: Column(children: [RaisedButton(onPressed: () {/// 实现点击事件debugPrint("命名路由导航跳转第二页");// 定义导航路由(导航到SecondRoute)/// 因为context是MyApp的BuildContext,MyApp不包含Navigator,因此报错/// Navigator必须在MaterialApp下一级/// push 的时候,增加路由跳转动画效果Navigator.push(context,PageRouteBuilder(/// 动画时长transitionDuration: Duration(milliseconds: 500),pageBuilder: (BuildContext context,Animation<double> animation,Animation<double> secondaryAnimation) {/// 嵌套一层渐变动画return FadeTransition(opacity: animation,/// 渐变动画+滑动动画child: SlideTransition(position: Tween<Offset>(begin: const Offset(1.0, 0.0),end: const Offset(0.0, 0.0),).animate(animation),///  child导航的第二个页面child: SecondRoute(),));}));},// 按钮显示内容child: Text("进入第二页"),)],),);}
}

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

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

相关文章

小功率电机驱动方案中如何选择驱动IC

小功率电机驱动方案及驱动IC的选择 电机驱动作为工业4.0中工厂自动化整个闭环中的执行器环节&#xff0c;其性能好坏直接影响到整个闭环的性能。因此&#xff0c;工业4.0对电机驱动提出了更高的性能和功能要求&#xff0c;例如更快的响应速度、更高的带宽、更高精度的位置和速…

前端框架中的路由(Routing)和前端导航(Front-End Navigation)

聚沙成塔每天进步一点点 本文回顾 ⭐ 专栏简介前端框架中的路由&#xff08;Routing&#xff09;和前端导航&#xff08;Front-End Navigation&#xff09;1. 路由&#xff08;Routing&#xff09;1.1 定义1.2 路由的核心概念1.2.1 路由表&#xff08;Route Table&#xff09;1…

多模态大模型:基础架构

大模型技术论文不断&#xff0c;每个月总会新增上千篇。本专栏精选论文重点解读&#xff0c;主题还是围绕着行业实践和工程量产。若在某个环节出现卡点&#xff0c;可以回到大模型必备腔调或者LLM背后的基础模型重新阅读。而最新科技&#xff08;Mamba,xLSTM,KAN&#xff09;则…

gitee添加别人的仓库后,在该仓库里添加文件夹/文件

一、在指定分支里添加文件夹&#xff08;如果库主没有创建分支&#xff0c;自己还要先创建分支&#xff09; eg:以在一个项目里添加视图文件为例&#xff0c;用Echarts分支在usr/views目录下添加Echarts文件夹&#xff0c;usr/views/Echarts目录下添加index.vue 1.切换为本地仓…

Linux系统安装Ruby语言

Ruby是一种面向对象的脚本语言&#xff0c;由日本的计算机科学家松本行弘设计并开发&#xff0c;Ruby的设计哲学强调程序员的幸福感&#xff0c;致力于简化编程的复杂性&#xff0c;并提供一种既强大又易于使用的工具。其语法简洁优雅&#xff0c;易于阅读和书写&#xff0c;使…

重学java 66.IO流 转换流

且敬我疯狂&#xff0c;生命中不败的篇章 —— 24.6.11 一、字符编码 计算机中储存的信息都是用二进制数表示的&#xff0c;而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制数转换之后的结果。[按照某种规则&#xff0c;将字符存储到计算机中&#xff0c;称为编…

打造一个属于你的桌面天气 超级有个性的天气桌面

打造一个属于你的桌面天气 超级有个性的天气桌面。大家好&#xff0c;今天我们带来一个非常有趣的桌面天气工具&#xff0c;喜欢桌面diy的你&#xff0c;快点用上它吧&#xff01; 桌面上的美化&#xff0c;是许多爱美用户的心血和热爱。每个地方的美化&#xff0c;都是自己亲…

机器学习课程复习——隐马尔可夫

不考计算题 Q:概率图有几种结构? 条件独立性的公式? 顺序结构发散结构汇总结构Q:隐马尔可夫模型理解? 概念 集合:状态集合、观测集合 序列:状态序列、观测序列

linux环境编程基础学习

Shell编程&#xff1a; 相对的chmod -x xx.sh可以移除权限 想获取变量的值要掏点dollar&#xff08;&#xff04;&#xff09; 多位的话要加个花括号 运算&#xff1a;expr 运算时左右两边必须要加空格 *号多个含义必须加转义符 双引号可以加反单&#xff0c;但是发过来就不行 …

【android】安卓入门学习

文档介绍&#xff1a;http://8.136.122.222/book/primary/kotlin/kotlin-intro.html 文档补充说明&#xff1a;https://blog.csdn.net/qq_42059717/category_12047508.html 一、搭建环境及工具安装 见文档 二、工具界面及项目文件介绍 ├── app //工程主模块名称 │ …

【Linux安装Conda环境的详细教程】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

PTP简介及Linux phy ptp驱动实现

1、PTP简介 PTP(precision time protocol)精确时间协议&#xff0c;是一种时间同步的协议&#xff0c;对应 IEEE 1588 标准&#xff0c;是基于网络数据包的一种时间同步协议&#xff0c;1588v2的同步精度可以达到ns级&#xff0c;但1588协议对硬件有依赖。 2、PTP原理 时间同…

DFS(一)

问题一(指数级选择) 从1~n这n个整数中任意选取多个&#xff0c;输出所有可能的选择方案。 首先想一下&#xff0c;在现实世界中&#xff0c;我们要如何解决这个问题。 应该是一个一个枚举&#xff0c;即每个数都可以有两个选择(选/不选)。共有种结果。 想一下&#xff0c;如…

PHP转Go系列 | 字符串的使用姿势

大家好&#xff0c;我是码农先森。 输出 在 PHP 语言中的输出比较简单&#xff0c;直接使用 echo 就可以。此外&#xff0c;在 PHP 中还有一个格式化输出函数 sprintf 可以用占位符替换字符串。 <?phpecho 码农先森; echo sprintf(码农:%s, 先森);在 Go 语言中调用它的输…

创建进程的常用方式

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 在Python中有多个模块可以创建进程&#xff0c;比较常用的有os.fork()函数、multiprocessing模块和Pool进程池。由于os.fork()函数只适用于Unix/Linu…

0617,递归问题(详细——好好好一入递归深似海)

目录 第七章&#xff08;函数&#xff09;思维导图总结&#xff1a;递归三问 01&#xff0c;电影院问题 理解递归的执行过程 02&#xff0c;FIBNACCI数列 不是说具有递归结构的问题&#xff0c;就可以用递归求解——存在大量的重复计算 法一&#xff1a;自顶向下求解 BUG…

ruoyi框架第二天,自定义接口,在若依框架显示数据

书接上文&#xff0c;搭建好若依&#xff0c;并且创建自己想要的模块。 让ruoyi框架显示自己想要的模块。 今天&#xff0c;我们就要自定义接口&#xff0c;模仿ruoyi框架收发数据模式&#xff0c;来创建自己的模块。 我们创建好自己想要的接口&#xff0c;我这个是无参的查…

【Java】已解决java.util.EmptyStackException异常

文章目录 一、问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决java.util.EmptyStackException异常 一、问题背景 java.util.EmptyStackException是Java在使用java.util.Stack类时可能会遇到的一个异常。这个异常通常在尝试从空的栈中弹出&am…

四连杆机构运动学仿真 | Matlab源码+理论文本【超详细】

【程序简介】&#x1f4bb;&#x1f50d; 本程序通过matlab实现了四连杆机构的运动学仿真编程&#xff0c;动态展现了四连杆机构的角位移、角速度和角加速度的时程曲线&#xff0c;除了程序本身&#xff0c;还提供了机构运动学详细的公式推导文档&#xff0c;从而帮助大家更好…

2024年化学、能源与核工程国际会议(ICCENE 2024)

2024年化学、能源与核工程国际会议(ICCENE 2024) 2024 International Conference on Chemical, Energy and Nuclear Engineering (ICCENE 2024) 会议地点&#xff1a;三亚&#xff0c;中国 网址&#xff1a;www.iccene.com 邮箱: iccenesub-conf.com 投稿主题请注明:ICCEN…