Flutter进阶—路由和导航
大部分应用程序都有多个屏幕或页面,并希望用户能从当前屏幕平滑过渡到另一个屏幕,Flutter的路由和导航功能可以帮助我们管理应用程序中的用户界面之间的命名和过渡。
管理多个用户界面有两个核心概念和类:路由(Route
)和导航器(Navigator
),路由(Route
)是应用程序的“屏幕”或“页面”的抽象,导航器(Navigator
)是管理路由的控件。导航器(Navigator
)可以推送(push
)和弹出(pop
)路由来帮助用户从当前屏幕移动到另一个屏幕。
使用导航器(Navigator)
移动应用通常通过称为“屏幕”或“页面”的全屏元素显示其内容,在Flutter中,这些元素称为路由,它们由导航器(Navigator
)控件管理。导航器管理一组路由(Route
)对象,并提供了管理堆栈的方法,例如Navigator.push
和Navigator.pop
。
Future push(BuildContext context,Route route
)
// 将给定的路由添加到最靠近给定上下文的导航器的历史记录,并过渡到它
bool pop(BuildContext context, [result
])
// 从导航器中弹出最靠近给定上下文的路由
显示屏幕路由
虽然您可以直接创建导航器,但最常见的是使用由WidgetsApp
或MaterialApp
控件创建的导航器,您可以使用Navigator.of
引用该导航器。
NavigatorState of(BuildContext context
)
// 最接近该类的实例包含给定上下文的状态
一个MaterialApp
是最简单的设置方式,MaterialApp
的home
成为导航器堆栈底部的路由。要在堆栈上推送(push
)一个新路由,您可以创建一个具有构建器功能的MaterialPageRoute
实例,它可以创建您想要显示在屏幕上的任何内容。
MaterialPageRoute
是一种模态路由,可以通过平台自适应过渡来切换屏幕。对于Android,页面推送过渡时向上滑动页面,并将其淡入淡出,弹出过渡则向下滑动页面,该过渡适应平台。在iOS上,页面从右侧滑入,反向弹出,当另一个页面进入以覆盖时,该页面也会在视差中向左移动。
默认情况下,当模态路由替换为另一路由时,上一个路由将保留在内存中,要在没有必要时释放所有资源,可以将maintainState
设置为false
。
现在我们新建一个项目myapp,然后用下面代码替换main.dart文件的代码:
import 'package:flutter/material.dart';void main() {runApp(new MyApp());
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return new MaterialApp(title: 'Flutter Demo',theme: new ThemeData(primarySwatch: Colors.blue,),home: new MyHomePage(title: '应用程序首页'),);}
}class MyHomePage extends StatefulWidget {MyHomePage({Key key, this.title}) : super(key: key);final String title;@override_MyHomePageState createState() => new _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {void _openNewPage() {setState(() {Navigator.of(context).push(new MaterialPageRoute<Null>(builder: (BuildContext context) {return new Scaffold(appBar: new AppBar(title: new Text('新的页面')),body: new Center(child: new Text('点击浮动按钮返回首页',),),floatingActionButton: new FloatingActionButton(onPressed: () {Navigator.of(context).pop();},child: new Icon(Icons.replay),),);},));});}@overrideWidget build(BuildContext context) {return new Scaffold(appBar: new AppBar(title: new Text(widget.title),),body: new Center(child: new Text('点击浮动按钮打开新页面',),),floatingActionButton: new FloatingActionButton(onPressed: _openNewPage,child: new Icon(Icons.open_in_new),),);}
}
通常没有必要提供一个使用Scaffold
在路由中弹出导航器的控件,因为Scaffold
会自动在其AppBar
中添加一个后退按钮。按下后退按钮会导致Navigator.pop
被调用,在Android上按系统后退按钮也是一样的。
使用命名导航器路由
移动应用程序经常管理大量路由,通常可以通过名称来引用它们。路由名称按惯例使用类似路径的结构,例如“/a/b/c”,应用程序的主页路由默认为“/”。
可以使用Map<String, WidgetBuilder>
创建MaterialApp
,该Map映射从路由的名称到将创建它的构建器,MaterialApp
使用此映射为导航器的onGenerateRoute
回调创建一个值。
import 'package:flutter/material.dart';void main() {runApp(new MyApp());
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return new MaterialApp(title: 'Flutter Demo',home: new MyHomePage(title: '应用程序首页'),routes: <String, WidgetBuilder> {'/a': (BuildContext context) => new MyPage(title: 'A 页面'),'/b': (BuildContext context) => new MyPage(title: 'B 页面'),'/c': (BuildContext context) => new MyPage(title: 'C 页面')},);}
}class MyHomePage extends StatefulWidget {MyHomePage({Key key, this.title}) : super(key: key);final String title;@override_MyHomePageState createState() => new _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {@overrideWidget build(BuildContext context) {return new Scaffold(appBar: new AppBar(title: new Text(widget.title),),body: new Row(children: <Widget>[new RaisedButton(child: new Text('A按钮'),onPressed: () { Navigator.of(context).pushNamed('/a'); },),new RaisedButton(child: new Text('B按钮'),onPressed: () { Navigator.of(context).pushNamed('/b'); },),new RaisedButton(child: new Text('C按钮'),onPressed: () { Navigator.of(context).pushNamed('/c'); },)]));}
}class MyPage extends StatelessWidget {MyPage({Key key, this.title}) : super(key: key);final String title;Widget build(BuildContext context) {return new Scaffold(appBar: new AppBar(title: new Text(title)),);}
}
Map<String, WidgetBuilder> routes
是应用程序的顶级路由表,当使用Navigator.pushNamed
推送命名路由时,将在此映射中查找路由名称。如果名称存在,则相关联的WidgetBuilder
将用于构造一个MaterialPageRoute
,该新的路由执行适当的过渡。
如果应用程序只有一个页面,那么可以使用home
指定它,如果指定了home
,那么在此映射中为Navigator.defaultRouteName
提供路由是一个错误。如果请求没有在此表中指定的路由(或通过home
),则会调用onGenerateRoute
回调来构建页面。
路由可以返回一个值
当路由被推送,用于获取用户的输入时,可以通过pop
方法的result
参数返回用户的输入值。推送路由的方法返回Future
类型,Future
将在路由弹出时解析,而Future
的值是pop
方法的result
参数。
例如,如果我们要求用户按“确定”确认操作,我们可以等待Navigator.push
的结果:
import 'package:flutter/material.dart';
import 'dart:async';void main() {runApp(new MyApp());
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return new MaterialApp(title: 'Flutter Demo',home: new MyHomePage(title: '应用程序首页'),);}
}class MyHomePage extends StatefulWidget {MyHomePage({Key key, this.title}) : super(key: key);final String title;@override_MyHomePageState createState() => new _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {bool _result = false;Future<Null> _openNewPage() async {bool value = await Navigator.of(context).push(new MaterialPageRoute<bool>(builder: (BuildContext context) {return new Center(child: new GestureDetector(child: new Text("确定"),onTap: () { Navigator.of(context).pop(true); },),);}));setState(() {_result = value;});}@overrideWidget build(BuildContext context) {return new Scaffold(appBar: new AppBar(title: new Text(widget.title),),body: new Center(child: new Text('用户当前选择为 $_result',),),floatingActionButton: new FloatingActionButton(onPressed: _openNewPage,child: new Icon(Icons.open_in_new),),);}
}
如果用户按“确定”,则值将为真。如果用户退出路由,例如通过按Scaffold
的后退按钮,该值将为null
。当使用路由return
值时,路由的type
参数必须与pop
的结果类型相匹配。这就是为什么我们使用MaterialPageRoute<bool>
而不是MaterialPageRoute<Null>
的原因。
弹出路由
路由不一定需要掩盖整个屏幕,PopupRoutes
覆盖屏幕,屏幕颜色只能部分不透明,以允许当前屏幕显示。弹出路由是模态的,因为它们阻止了下面的控件的输入。
框架有创建和显示弹出路由的功能,例如:showDialog
、showMenu
和showModalBottomSheet
。这些功能如上所述返回其推送的路由的Future
,调用时可以等待返回的值在路由弹出时采取行动,或者发现路由的值。
还有一些创建弹出路由的控件,如PopupMenuButton
和DropdownButton
。这些控件创建PopupRoute
的内部子类,并使用路由的push
和pop
方法来显示和关闭它们。
import 'package:flutter/material.dart';
import 'dart:async';void main() {runApp(new MyApp());
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return new MaterialApp(title: 'Flutter Demo',home: new MyHomePage(title: '应用程序首页'),);}
}class MyHomePage extends StatefulWidget {MyHomePage({Key key, this.title}) : super(key: key);final String title;@override_MyHomePageState createState() => new _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {bool _result = false;Future<Null> _openNewPage() async {bool value = await showDialog(context: context,barrierDismissible: true,child: new Center(child: new GestureDetector(child: new Text("确定"),onTap: () { Navigator.of(context).pop(true); },),));setState(() {_result = value;});}@overrideWidget build(BuildContext context) {return new Scaffold(appBar: new AppBar(title: new Text(widget.title),),body: new Center(child: new Text('用户当前选择为 $_result',),),floatingActionButton: new FloatingActionButton(onPressed: _openNewPage,child: new Icon(Icons.open_in_new),),);}
}
定制路由
您可以创建自己的控件库路由类,比如PopupRoute
、ModalRoute
或PageRoute
的子类,以控制用于显示路由,包括路由模态屏障的颜色和行为以及路由其他方面的动画转换。
PageRouteBuilder
类可以根据回调来定义自定义路由,下面是一个示例,当路由出现或消失时,它会旋转和淡化其子对象。此路由不会遮蔽整个屏幕,因为它指定了opaque: false
,就像弹出路由一样。
import 'package:flutter/material.dart';void main() {runApp(new MyApp());
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return new MaterialApp(title: 'Flutter Demo',home: new MyHomePage(title: '应用程序首页'),);}
}class MyHomePage extends StatefulWidget {MyHomePage({Key key, this.title}) : super(key: key);final String title;@override_MyHomePageState createState() => new _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {void _openNewPage() {Navigator.of(context).push(new PageRouteBuilder(opaque: false,pageBuilder: (BuildContext context, _, __) {return new Center(child: new Text('定制页面路由'));},transitionsBuilder: (_, Animation<double> animation, __, Widget child) {return new FadeTransition(opacity: animation,child: new RotationTransition(turns: new Tween<double>(begin: 0.5, end: 1.0).animate(animation),child: child,),);}));}@overrideWidget build(BuildContext context) {return new Scaffold(appBar: new AppBar(title: new Text(widget.title),),body: new Center(child: new Text('点击浮动按钮打开定制页面',),),floatingActionButton: new FloatingActionButton(onPressed: _openNewPage,child: new Icon(Icons.open_in_new),),);}
}
页面路由分为两部分:“页面”和“过渡”。页面成为传递给buildTransitions
方法的子代的后代,通常,页面仅构建一次,因为它不依赖于其动画参数,在此示例中为_
和__
。过渡建立在每个帧的持续时间。
Flutter进阶—路由和导航相关推荐
- Flutter之路由与导航
先放效果,瞎写一通,不过我发现自己挺享受自己创作设计的过程的,真的废寝忘食hhh 贴代码 //main.dartimport 'package:flutter/material.dart'; impo ...
- Flutter代码锦囊---集中管理路由与导航
当一个Flutter项目的页面多来以后,页面跳来跳去的,开发者自己都会晕,所以需要用一个集中.灵活的方式去管理项目中所有页面的路由与导航. 通常我们是使用主页(home)属性设置应用程序的默认路由,即 ...
- Flutter——路由和导航
Flutter--路由和导航 引文 入栈 出栈 实战 效果图 释 商品导航页 商品实体类 商品展示 商品详情页 商品图片 商品信息 引文 先简单了解一下Flutter页面之间路由,然后通过一个简答实例 ...
- 阿里内部总结“Flutter进阶笔记”,你收藏好了嘛?
每一个移动开发者都在为 Flutter 带来的"快速开发.富有表现力和灵活的 UI.原生性能"的特色和理念而痴狂,从超级 App 到独立应用,从纯 Flutter 到混合栈,开发者 ...
- ALI Flutter进阶笔记,移动手机app开发
阿里巴巴集团内也有越来越多的业务和团队开始尝试 Flutter 技术栈,从闲鱼的一支独秀引领潮流,到如今淘宝特价版.优酷.飞猪等BU业务相继入局,Flutter的业务应用在集团内也已经逐渐形成趋势. ...
- ALI Flutter进阶笔记
每一个移动开发者都在为 Flutter 带来的"快速开发.富有表现力和灵活的 UI.原生性能"的特色和理念而痴狂,从超级 App 到独立应用,从纯 Flutter 到混合栈,开发者 ...
- Flutter进阶—简单平台插件实例
在之前写过的<Flutter进阶-平台插件>中,笔者简单介绍了如何简单的使用和创建一个Flutter插件,现在可以试试编写一个可以在平台与客户端之间传递数据的Flutter平台插件.在此之 ...
- Flutter进阶学习
文章目录 [Flutter学习]事件处理与通知之事件处理 - GestureDetector [Flutter学习]页面跳转之路由及导航 Route + Navigator --- pushRepla ...
- vue axios跨域请求_axios的请求拦截和vue路由的导航守卫有什么区别
在Vue项目中,有两种用户登录状态判断并处理的情况,分别为:导航守卫和axios拦截器. 1. 导航守卫:拦截组件 导航守卫就是我们进行某些页面的时候需要判断当前用户是否登录过,如果登陆过,则可以跳转 ...
最新文章
- 亿级流量网关设计思路
- 解决gitosis.init.InsecureSSHKeyUsername: Username contains not allowed characters问题
- Oracle闪回详解
- 前端 相机 自定义取景框_索尼ZV-1数码相机:专业而易用,Vlog和网络主播的进阶良机...
- Linux集中日志服务器rsyslog(亲测)
- PHP APM 对比评测:OneAPM, New Relic, 听云
- SQL Server编程(01)流程控制
- 计算机插本2a院校,广东省专插本2A院校有哪些
- Linux学习笔记(更新中)
- 二叉树的叶结点/ 树的深度计算
- 【玩转嵌入式屏幕显示】(六)ST7789 SPI LCD硬件垂直滚动功能的使用
- 新书推荐 |《深入浅出Serverless:技术原理与应用实践》
- 打开html按钮没文字,为什么我打开网页有些字没显示但能点击
- spark(day05)
- ESP32系列:Unhandled debug exception 、Doubled exception错误
- 精选100个毕业答辩PPT模板
- 忆阻器交叉开关阵列中的长短期记忆(LSTM)神经网络
- matlab进行mppt控制仿真,基于matlab光伏发电系统的MPPT控制与仿真.pdf
- Tensorflow新版Seq2Seq接口使用
- 基于微信小程序的校园跑腿系统
热门文章
- PL-SVO: Semi-Direct Monocular Visual Odometry by Combining Points and Line Segments
- npm下载缓慢解决方法
- BasicAuth和OAuth
- JavaScript内建对象 (一) ----- Array
- 面试题 01.01. 判定字符是否唯一 (计数排序思想)
- 常用类 (七) ----- 包装类
- 使用NodeJS连接到MySQL数据库Client does not support authentication protocol requested by server; consider upg
- struts2学习笔记(一) MVC模式
- EasyUI 添加一行的时候 行号出现负数的解决方案
- 第一次使用并配置Hibernate