routes: {
"/router": (context) => RouterDemo(),
"/router/nextPage": (context) => NextPage2(),
Navigator.of(context).pop(); //直接做退出操作
Navigator.of(context).maybePop(); //若为栈中最后一个页面不做退出操作
popAndPushNamed
退出当前页面并跳转新页面
Navigator.of(context).popAndPushNamed("/router/nextPage");
等同于如下操作
Navigator.of(context).pop();
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => NextPage1(),
PS: 但需要注意如果当前页为栈底根页面先执行pop再执行push会不会和popAndPushNamed执行结果不同呢?看源码就能会发现popAndPushNamed其实就是先执行pop再执行push的操作所以两者执行结果一样。
@optionalTypeArgs
Future<T> popAndPushNamed<T extends Object, TO extends Object>(
String routeName, {
TO result,
Object arguments,
pop<TO>(result);
return pushNamed<T>(routeName, arguments: arguments);
pushReplacementNamed
用法和popAndPushNamed类似,同样是退出当前页面并跳转新页面。但popAndPushNamed页面出栈和入栈都有动画,pushReplacementNamed则只有入栈动画
Navigator.of(context).pushReplacementNamed("/router/next5");
pushNamedAndRemoveUntil
将路由栈出栈到对应命名路由然后跳转到新页面,如下所示代码“ModalRoute.withName("/")”是将路由栈退到根路由并跳转到“/router/nextPage”命名路由。 举例当前路由栈为[1,2,3,4],执行pushNamedAndRemoveUntil打开新页面5,设置 ModalRoute.withName为2,最后路由栈为[1,2,5]。常用场景例如在个人设置页面中多级子菜单跳转最后直接回到主页操作。
Navigator.of(context).pushNamedAndRemoveUntil(
"/router/nextPage",
ModalRoute.withName("/"),
PS: 这里要注意的是如果入栈非命名路由,不采用pushNamed入栈则ModalRoute.withName("/")会找不到要回退的位置,则跳转的页面不带返回键,也就是说栈中就只剩下一个页面。这点真的好奇是不是Flutter路由设计的问题,我暂时也没有找到ModalRoute.withName替代方法所以回退的页面路由必须是命名路由。
removeRoute
路由栈移除功能,例如可以通过ModalRoute.of(context)获取当前页面路由。如果和Navigator.of(context).pop()做比较的话就是通过该方法可以移除指定路由,只要拿到对应路由对象就能将其在栈中移除。而Navigator.of(context).pop()则只能移除当前路由页面。
Navigator.of(context).removeRoute(ModalRoute.of(context));
removeRouteBelow
同样是路由栈移除功能,根据输入页面路由移除该锚点路由的上一个页面路由。 例如路由栈为[1,2,3,4],执行removeRouteBelow(3)后路由栈变为[1,3,4]。
Navigator.of(context).removeRouteBelow(ModalRoute.of(context));
replace
替换路由栈功能,类似于pushReplacementNamed。
PS:The old route must not be currently visible 在官方文档中对replace方法的介绍,不能用于栈顶路由。所以该方法并不能用做当前路由使用,可以移除上一个或栈中路由。
因此这里终于可用使用到UserNavigatorObserver中全局路由栈数组history获取指定路由将其从栈中移除。
Navigator.of(context).replace(
oldRoute: UserNavigatorObserver
.history[UserNavigatorObserver.history.length - 2],
newRoute: MaterialPageRoute(
builder: (_) => NextPage1(),
例如路由栈为[1,2,3,4],replace(3,5)后路由栈变为[1,2,5,4]。
replaceRouteBelow
替换路由栈功能,于removeRouteBelow同理。替换输入路由替换掉该锚点路由的上一个页面路由。最后和replace一样不能作用于当前页面路由。
Navigator.of(context).replaceRouteBelow(
anchorRoute: UserNavigatorObserver
.history[UserNavigatorObserver.history.length - 2],
newRoute: MaterialPageRoute(
builder: (_) => NextPage1(),
例如路由栈为[1,2,3,4],replace(3,5)后路由栈变为[1,5,3,4]。
路由同时支持页面之间的参数传递
路由跳转通过arguments字段传递想要的入参数据,我们可以设定arguments为map对象传递更多入参。命名路由和直接路由传递arguments略有不同,命名路由直接通过arguments字段传递,直接路由是通过settings字段创建RouteSettings对象中的arguments传递。
Navigator.of(context).pushNamed(
"/router/data2",
arguments: {"data": "Hello"},
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ChildDataDemo4(),
settings: RouteSettings(
arguments: {"data": "Hello"},
接收页面通过ModalRoute.of(context).settings获取入参arguments得到数据。
class RouterChildDateDemo2 extends StatefulWidget {
@override
_RouterChildDateDemo2State createState() => _RouterChildDateDemo2State();
class _RouterChildDateDemo2State extends State<RouterChildDateDemo2> {
@override
Widget build(BuildContext context) {
Map arguments = ModalRoute.of(context).settings.arguments;
String data = arguments['data'];
return Scaffold(
appBar: AppBar(),
body: Column(
children: <Widget>[
Text("data: $data"),
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ChildDateDemo3("Hello"),
数据接收页面通过widget获取入参。当然这种方式耦合性太高,对后期维护不利不推荐使用(虽然我自己项目中都是这么写,之后重构工作量巨大😿)。
class ChildDateDemo3 extends StatefulWidget {
final String data;
ChildDateDemo3(this.data);
@override
_ChildDateDemo3State createState() => _ChildDateDemo3State();
class _ChildDateDemo3State extends State<ChildDateDemo3> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
children: <Widget>[
Text("data: ${widget.data}"),
由于context上下文的缘故若传参需要在initState中使用时,使用SchedulerBinding.instance.addPostFrameCallback获取参数。
SchedulerBinding.instance.addPostFrameCallback((_) {
Map arguments = ModalRoute.of(context).settings.arguments;
cusip = arguments["cusip"];
除了入参外,我们当然希望能够在传递参数同时可以获取到返回值。比如进入一个设置页面在返回时获取到上个页面设置数据并显示(虽然全局状态管理就能很好代替这方式)。
路由跳转方法是有返回值Future,将跳转方法设置为async通过await获取结果。
var result = await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ChildDataDemo5(),
setState(() {
this.result = result.toString();
当要返回上级页面回传结果时在pop方法中传递需要返回泛型参数(使用字典是比较好的数据结构)。
Navigator.of(context).pop({"data": "Bye"});
替换MaterialPageRoute使用PageRouteBuilder做路由跳转。通过transitionsBuilder创建AnimatedWidget对象实现动画效果。如下设置一个SlideTransition滑动过渡动画通过起始和结束的偏移量达到侧边滑出效果
Navigator.of(context).push(
PageRouteBuilder(
pageBuilder: (BuildContext context,
Animation<double> animation1,
Animation<double> animation2) {
return AniDemo2();
transitionsBuilder: (BuildContext context,
Animation<double> animation1,
Animation<double> animation2,
Widget child) {
return SlideTransition(
position: Tween<Offset>(
begin: Offset(-1.0, 0.0),
end: Offset(0.0, 0.0),
).animate(
animation1,
child: child,
路由全局监听
路由同时支持监听功能,通过NavigatorObserver可以实时获取路由进栈出栈信息。在根组件中创建路由观察者NavigatorObserver,如下创建UserNavigatorObserver继承NavigatorObserver通过回调接口记录全局栈信息。下面就介绍NavigatorObserver回调接口的触发条件。
MaterialApp(
navigatorObservers: [UserNavigatorObserver()],
......
继承实现NavigatorObserver并增加全局history栈信息管理数组。
class UserNavigatorObserver extends NavigatorObserver {
static List<Route<dynamic>> history = <Route<dynamic>>[];
@override
void didPop(Route route, Route previousRoute) {
super.didPop(route, previousRoute);
history.remove(route);
///调用Navigator.of(context).pop() 出栈时回调
@override
void didPush(Route route, Route previousRoute) {
super.didPush(route, previousRoute);
history.add(route);
///调用Navigator.of(context).push(Route()) 进栈时回调
@override
void didRemove(Route route, Route previousRoute) {
super.didRemove(route, previousRoute);
history.remove(route);
///调用Navigator.of(context).removeRoute(Route()) 移除某个路由回调
@override
void didReplace({Route newRoute, Route oldRoute}) {
super.didReplace(newRoute: newRoute, oldRoute: oldRoute);
history.remove(oldRoute);
history.add(newRoute);
///调用Navigator.of(context).replace( oldRoute:Route("old"),newRoute:Route("new")) 替换路由时回调
@override
void didStartUserGesture(Route route, Route previousRoute) {
super.didStartUserGesture(route, previousRoute);
///iOS侧边手势滑动触发回调 手势开始时回调
@override
void didStopUserGesture() {
super.didStopUserGesture();
///iOS侧边手势滑动触发停止时回调 不管页面是否退出了都会调用
didPop
调用Navigator.of(context).pop()或其他出栈方法时回调
didPush
调用Navigator.of(context).push(Route())或其他进栈方法时回调
didRemove
调用Navigator.of(context).removeRoute(Route()) 移除某个路由回调
didReplace
调用Navigator.of(context).replace( oldRoute:Route("old"),newRoute:Route("new")) 替换路由时回调
didStartUserGesture
iOS侧边手势滑动触发回调 手势开始时回调
didStopUserGesture
iOS侧边手势滑动触发停止时回调 不管页面是否退出了都会调用
🚀完整代码看这里🚀
作者:JulyYu
链接:https://juejin.im/post/5d5f7d10f265da03963ba174
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
跳转功能举例常用页面跳转功能。普通跳转 Navigator.of(context).push( MaterialPageRoute( builder: (_) => NextPage1(), ), );复制代码命名跳转Navigator.of(context).pushNamed("/router/nextPage");复制代码前提是需要在程序主入口配置路由表MaterialApp( navigatorObserver
什么是Router
Android中,页面对应的是Activity,在iOS中是ViewController。而在Flutter中,页面只是一个widget,是Router。Route 在Android 中通常指一个 Activity ,在 iOS 中指一个 ViewController
MaterialPageRoute
MaterialPageRoute继承自PageRoute类,PageRoute类是一个抽象类,表示占有整个屏幕空间的一个模态路由页面,它还定义了路由构建及切换时过渡动画的相关
Flutter中,路由(Router)即页面的封装,一个路由内部包含了一个页面。创建路由:
MaterialPageRoute route = MaterialPageRoute(
builder: (BuildContext context) => MyPage(),
类似于在Android原生中以任务栈来管理Activity,在Flutter中以路由栈来管理路由。跳转到...
Navigator 继承自 StatefulWidget,它也是小组件,它有很多相关静态函数,可以帮我们达到页面跳转和数据交互的功能:
push 将设置的router信息推送到Navigator上,实现页面跳转。
of 主要是获取 Navigator最近实例的好状态。
pop 导航到新页面,或者返回到上个页面。
canPop 判断是否可以导航到新页面
maybePop 可能会导航到新页面
@optionalTypeArgs
static Future<T?> push<T extends Object?>(BuildContext context, Route<T> route) {
return Navigator.of(context).push(route);
Navigator.push需要传入两个参数,分别为cont.
老孟导读:很多时候我们需要监听路由堆栈的变化,这样可以自定义路由堆栈、方便分析异常日志等。
监听路由堆栈的变化使用 RouteObserver ,首先在 MaterialApp 组件中添加 navigatorObservers:
void main() {
runApp(MyApp());
RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
class MyApp extends ..
简略版:(tips:不只刷新会出问题,输入网址导航也会)
1、刷新404:将匹配全部为定义路径到404的路由从静态路由表中去除,在动态权限路由都添加了之后在添加。接下来可能会报warn并白屏,解决方法见下一条2。
2、刷新白屏:如果是在路由守卫router.beforeEach中检测并用router.addRoute添加的路由,则需要将动态权限路由添加后的next()放行,改为next(to)触发
原文地址: Flutter 路由使用
路由(Route)在移动开发中通常指页面(Page),这跟web开发中单页应用的Route概念意义是相同的,Route在Android中通常指一个Activity,在iOS中指一个ViewController。Flutter中,Route的管理是在内部维护一个路由栈,通过 Navigator 的 push、pop操作,实现路由的入栈和出栈操作,达到页面开启关闭的效果。
1.构建路由的两种方式
Flutter中,构建路由存在两种方式:普通路由 与 命名路由。普通路由
Flutter 1.22发布带来了 Navigator2.0 , 给了开发者更多选择,你可以灵活地管理路由栈,可以处理在浏览器里面输入的情况,也可以嵌套多个Navigator,虽然仍然有缺点,但是基本上可以做到路由我定。下面跟我一起走进 Flutter 路由的世界。本文源码版本为Flutter Stable 1.22.6。
路由基础...
Flutter 是 Google 推出的一款跨平台移动应用开发框架,能够同时在 Android 和 iOS 上构建高性能的原生应用。Flutter 非常适合开发复杂的应用程序,其中包括需要大量数据呈现和处理的 PDF 文件。
为了在 Flutter 中实现 PDF 阅读,我们可以使用第三方库实现此功能。 Dart PDF 是一款用 Dart 编程语言编写的 PDF 处理库,它能够解析 PDF 文件并提取出文件中的文字、图片和属性等内容。使用 Dart PDF,我们可以在 Flutter 应用程序中轻松地加载、查看和处理 PDF 文件。
Flutter 实战 PDF 可能需要掌握以下技能:
1. 加载 PDF 文件:通过 Dart PDF 库提供的 API,我们可以找到要加载的 PDF 文件并提取其内容。
2. 显示 PDF 文件:为了在 Flutter 的应用程序中显示 PDF 文件,我们可以使用打包的 WebView 或其他 PDF 阅读器库。
3. 实现 PDF 阅读器功能:在阅读 PDF 文件时,用户可能需要缩放、翻页、搜索和标注 PDF 文档。为了实现这些功能,需要使用 Flutter 提供的控件和 Dart PDF 库提供的文档 API。
总体来说,Flutter 实战 PDF 在移动应用程序开发中非常重要。 Flutter 与 Dart PDF 库的结合使开发人员能够轻松地构建和处理 PDF 文件。如果您想成为一名高效的 Flutter 开发人员,掌握 Flutter 实战 PDF 将是一个非常有用的技能。