热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

代码跳转路由报错_flutter路由

路由管理控制路由是一个应用程序抽象的屏幕或页面;路由管理就是管理页面之间如何跳转;路由入栈指打开一个新页面;路由出栈指一个页面关闭操作&#

路由管理控制

  • 路由是一个应用程序抽象的屏幕或页面;
  • 路由管理就是管理页面之间如何跳转;
  • 路由入栈指打开一个新页面;
  • 路由出栈指一个页面关闭操作;
  • 路由管理指如何来管理路由栈;
  • Navigator是一个管理路由的widget;
  • NavigatorKey是一个管理路由的Key;

看完本文你将学会路由的使用管理好一个路由路由传参路由带参返回路由记录返回到指定路由路由动画, 然后使用pop操作来进行回退到某个路由;

Navigator

方法作用

开始上手

我们创建个普通路由跳转,跳转到原页面,但是标题的数量会+1,让我们知道当前是push到的第几个页面;

路由跳转传参示例:

import 'package:flutter/material.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return new MaterialApp(title: 'Flutter高级进阶',home: new MyHomePage(),);}
}class MyHomePage extends StatefulWidget {// 接收的num参数final int num;// MyHomePage不写参数则默认为1MyHomePage({this.num = 1});@override_MyHomePageState createState() => _MyHomePageState();
}class _MyHomePageState extends State {@overrideWidget build(BuildContext context) {return new Scaffold(// 显示接收的num参数appBar: new AppBar(title: new Text('Flutter高级进阶${widget.num}')),// 按钮点击执行跳转方法body: new FlatButton(child: new Text("push"), onPressed: () => push()),);}/** 路由跳转方法* */push() {// 拿到传过来的num然后+1 int num = widget.num + 1;//导航到新路由Navigator.push(context,MaterialPageRoute(// num传给下一级builder: (context) => MyHomePage(num: num)),);}
}

效果图:

bad15ead8ccd71dd2b374567a97fa504.gif

错误示例:

class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return new MaterialApp(title: 'Flutter高级进阶',home: new Scaffold(appBar: new AppBar(),body: new FlatButton(child: new Text("push"), onPressed: () => push(context)),),);}/** 路由跳转方法* */push(context) {//导航到新路由Navigator.push(context,MaterialPageRoute(// MyHomePage不写参数则默认为1builder: (context) => MyHomePage()),);}
}

报错信息:

I/flutter (21935): ══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
I/flutter (21935): The following assertion was thrown while handling a gesture:
I/flutter (21935): Navigator operation requested with a context that does not include a Navigator.
I/flutter (21935): The context used to push or pop routes from the Navigator must be that of a widget that is a
I/flutter (21935): descendant of a Navigator widget.
I/flutter (21935):
I/flutter (21935): When the exception was thrown, this was the stack:
I/flutter (21935): #0 Navigator.of. (package:flutter/src/widgets/navigator.dart:1475:9)
I/flutter (21935): #1 Navigator.of (package:flutter/src/widgets/navigator.dart:1482:6)
I/flutter (21935): #2 Navigator.push (package:flutter/src/widgets/navigator.dart:1107:22)
I/flutter (21935): #3 MyApp.push (package:oc_project/main.dart:18:15)
I/flutter (21935): #4 MyApp.build. (package:oc_project/main.dart:12:72)
I/flutter (21935): #5 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:654:14)
I/flutter (21935): #6 _InkResponseState.build. (package:flutter/src/material/ink_well.dart:729:32)
I/flutter (21935): #7 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
I/flutter (21935): #8 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:365:11)
I/flutter (21935): #9 TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:275:7)
I/flutter (21935): #10 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:455:9)
I/flutter (21935): #11 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:75:13)
I/flutter (21935): #12 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:102:11)
I/flutter (21935): #13 GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:218:19)
I/flutter (21935): #14 GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:198:22)
I/flutter (21935): #15 GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:156:7)
I/flutter (21935): #16 GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:102:7)
I/flutter (21935): #17 GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:86:7)
I/flutter (21935): #21 _invoke1 (dart:ui/hooks.dart:263:10)
I/flutter (21935): #22 _dispatchPointerDataPacket (dart:ui/hooks.dart:172:5)
I/flutter (21935): (elided 3 frames from package dart:async)
I/flutter (21935):
I/flutter (21935): Handler: "onTap"
I/flutter (21935): Recognizer:
I/flutter (21935): TapGestureRecognizer#72729

这个报错是因为用的这个上下文是MaterialApp的,这个上下文不包含Navigator导航器操作, 所以我们应该把home的那部分抽出来放另一个类;

路由传值并返回值

路由传参在上面那个例子已经有了,num就是我们的参数,然后显示在标题上就是使用了。

这节教大家路由传值并返回值,创建个NewPage,接收个文本值text,然后显示在新页面,新页面给个返回按钮, 点击返回按钮返回并带回一串值回去。

NewPage:

class NewPage extends StatelessWidget {final String text;NewPage({@required this.text, // 接收一个text参数});@overrideWidget build(BuildContext context) {return new Scaffold(appBar: new AppBar(title: new Text("新页面:$text")),body: new RaisedButton(onPressed: () => Navigator.pop(context, "我是返回值"),child: new Text("返回"),),);}
}

然后之前写好的push方法改下,用then接收:

/** 路由跳转方法* */
push() {//导航到新路由Navigator.push(context,MaterialPageRoute(// 拿到传过来的num然后++传给下一级builder: (context) => NewPage(text: '参数'),),).then((value) {if (value != null) print('接收到的参数:$value');});
}

这样我们就能push到新页面然后点击返回按钮就能把参数返回到push到它的那个方法,然后在then打印出来了:

I/flutter (21935): 接收到的参数:我是返回值

直接点击左上角那个返回值会为空,这样打印出来的就是:

I/flutter (21935): 接收到的参数:null

所以我们做了一个判断,不为空才执行打印,如果为空就不做任何操作;

路由命名

我们想执行跟name有关的Navigator方法就必须先给路由命名,比如pushNamed方法, 注册路由在MaterialApproutes属性,它的定义为:

final Map routes;

注册示例

class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return new MaterialApp(title: 'Flutter高级进阶',routes: {"newPage": (context) => new NewPage(text: '注册路由名的新页面'),},home: new MyHomePage(),);}
}

这样我们的newPage就注册好了,然后试试pushNamed方法:

/** 路由跳转方法* */
push() {Navigator.pushNamed(context, "newPage").then((value) {if (value != null) print('接收到的参数:$value');});
}

效果图:

14d17584b5c4de984a791d8b163e50d2.gif

返回到指定路由

这节我们使用popUntil方法返回到我们想要返回到的某个路由,首先再注册两个路由名:

@override
Widget build(BuildContext context) {return new MaterialApp(title: 'Flutter高级进阶',routes: {// 新页面路由名"newPage": (context) => new NewPage(text: '注册路由名的新页面'),// 第二个路由名"towPage": (context) => new TowPage(),// 首页路由名"/": (context) => new MyHomePage(),},
// home: new MyHomePage(), 这个必须注释,因为我们注册了根路由名:"/",否则报错);
}

TowPage:

class TowPage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: new AppBar(title: new Text('页面二')),body: new RaisedButton(onPressed: () => Navigator.popUntil(context, ModalRoute.withName('/')),child: new Text("返回到首页"),),);}
}

然后NewPage把返回改成push到第二个页面:

class NewPage extends StatelessWidget {final String text;NewPage({@required this.text, // 接收一个text参数});@overrideWidget build(BuildContext context) {return new Scaffold(appBar: new AppBar(title: new Text("新页面:$text")),body: new RaisedButton(onPressed: () => Navigator.pushNamed(context, "towPage"),child: new Text("到第二个页面"),),);}
}

效果图:

1a337c7acd8d860cac92b2a154cd1ff7.gif

这样就实现了到第二个页面的时候点击回到首页按钮就直接返回到首页了。

路由记录

我们每次跳转一个新路由然后想返回到之前跳转过的某个路由难道每个都要注册路由名吗?那样的话太麻烦了, 这节就教大家路由记录,只要我们跳转过某个路由就记录起来, 然后最后面的路由想返回到前面的三个中的某个都不需要配置名字了。

配置:

/** 路由跳转方法* */
push() {Navigator.push(context,MaterialPageRoute(builder: (context) => MyHomePage(),settings: new RouteSettings(name: MyHomePage().toStringShort(), // 设置的路由名isInitialRoute: false, // 是否初始路由),),);
}

这样我们就把我们要跳转到的MyHomePage跳转了,同时还记录了路由名字;

使用:

class TowPage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: new AppBar(title: new Text('页面二')),body: new RaisedButton(onPressed: () => Navigator.popUntil(context,// 使用记录好的路由名字ModalRoute.withName(MyHomePage().toStringShort()),),child: new Text("返回到MyHomePage"),),);}
}

这样我们就可以完美的返回到MyHomePage页面了,使用起来非常方便。

路由动画理论

路由动画就是我们跳转到下一个路由栈的时候所产生的过度动画,官方提供了两个动画: MaterialPageRouteCupertinoPageRoute;

解释:

  • MaterialPageRoute:存在于:import 'package:flutter/material.dart';包;
  • CupertinoPageRoute:存在于:import 'package:flutter/cupertino.dart';包;

使用:

直接把我们用来push的MaterialPageRoute更改为:CupertinoPageRoute即可查看动画效果;

自定义路由动画

首先编写好一个路由动画,路由动画必须继承至PageRouteBuilder:

/*
* 渐变动画
* */
class FadeRoute extends PageRouteBuilder {// 传过来的页面pagefinal Widget page;// 构造FadeRoute({this.page}): super(pageBuilder: (BuildContext context,Animation animation,Animation secondaryAnimation,) =>page,transitionsBuilder: (BuildContext context,Animation animation,Animation secondaryAnimation,Widget child,) =>FadeTransition(opacity: animation, // 透明度child: child, // 页面存放),);
}

然后push方法直接更改为:

push() {Navigator.push(context,FadeRoute(page: MyHomePage()),);
}




推荐阅读
  • 本文介绍了在 Java 编程中遇到的一个常见错误:对象无法转换为 long 类型,并提供了详细的解决方案。 ... [详细]
  • 实验九:使用SharedPreferences存储简单数据
    本实验旨在帮助学生理解和掌握使用SharedPreferences存储和读取简单数据的方法,包括程序参数和用户选项。 ... [详细]
  • 使用 ListView 浏览安卓系统中的回收站文件 ... [详细]
  • 深入解析 Android 中 EditText 的 getLayoutParams 方法及其代码应用实例 ... [详细]
  • 本文介绍了一种自定义的Android圆形进度条视图,支持在进度条上显示数字,并在圆心位置展示文字内容。通过自定义绘图和组件组合的方式实现,详细展示了自定义View的开发流程和关键技术点。示例代码和效果展示将在文章末尾提供。 ... [详细]
  • Python 程序转换为 EXE 文件:详细解析 .py 脚本打包成独立可执行文件的方法与技巧
    在开发了几个简单的爬虫 Python 程序后,我决定将其封装成独立的可执行文件以便于分发和使用。为了实现这一目标,首先需要解决的是如何将 Python 脚本转换为 EXE 文件。在这个过程中,我选择了 Qt 作为 GUI 框架,因为之前对此并不熟悉,希望通过这个项目进一步学习和掌握 Qt 的基本用法。本文将详细介绍从 .py 脚本到 EXE 文件的整个过程,包括所需工具、具体步骤以及常见问题的解决方案。 ... [详细]
  • 分享一款基于Java开发的经典贪吃蛇游戏实现
    本文介绍了一款使用Java语言开发的经典贪吃蛇游戏的实现。游戏主要由两个核心类组成:`GameFrame` 和 `GamePanel`。`GameFrame` 类负责设置游戏窗口的标题、关闭按钮以及是否允许调整窗口大小,并初始化数据模型以支持绘制操作。`GamePanel` 类则负责管理游戏中的蛇和苹果的逻辑与渲染,确保游戏的流畅运行和良好的用户体验。 ... [详细]
  • 微信小程序实现类似微博的无限回复功能,内置云开发数据库支持
    本文详细介绍了如何利用微信小程序实现类似于微博的无限回复功能,并充分利用了微信云开发的数据库支持。文中不仅提供了关键代码片段,还包含了完整的页面代码,方便开发者按需使用。此外,HTML页面中包含了一些示例图片,开发者可以根据个人喜好进行替换。文章还将展示详细的数据库结构设计,帮助读者更好地理解和实现这一功能。 ... [详细]
  • 深入解析:React与Webpack配置进阶指南(第二部分)
    在本篇进阶指南的第二部分中,我们将继续探讨 React 与 Webpack 的高级配置技巧。通过实际案例,我们将展示如何使用 React 和 Webpack 构建一个简单的 Todo 应用程序,具体包括 `TodoApp.js` 文件中的代码实现,如导入 React 和自定义组件 `TodoList`。此外,我们还将深入讲解 Webpack 配置文件的优化方法,以提升开发效率和应用性能。 ... [详细]
  • 在Python中,是否可以通过使用Tkinter或ttk库创建一个具有自动换行功能的多行标签,并使其宽度能够随着父容器的变化而动态调整?例如,在调整NotePad窗口宽度时,实现类似记事本的自动换行效果。这种功能在设计需要显示长文本的对话框时非常有用,确保文本内容能够完整且美观地展示。 ... [详细]
  • 开发笔记:深入解析Android自定义控件——Button的72种变形技巧
    开发笔记:深入解析Android自定义控件——Button的72种变形技巧 ... [详细]
  • Android 图像色彩处理技术详解
    本文详细探讨了 Android 平台上的图像色彩处理技术,重点介绍了如何通过模仿美图秀秀的交互方式,利用 SeekBar 实现对图片颜色的精细调整。文章展示了具体的布局设计和代码实现,帮助开发者更好地理解和应用图像处理技术。 ... [详细]
  • Android目录遍历工具 | AppCrawler自动化测试进阶(第二部分):个性化配置详解
    终于迎来了“足不出户也能为社会贡献力量”的时刻,但有追求的测试工程师绝不会让自己的生活变得乏味。与其在家消磨时光,不如利用这段时间深入研究和提升自己的技术能力,特别是对AppCrawler自动化测试工具的个性化配置进行详细探索。这不仅能够提高测试效率,还能为项目带来更多的价值。 ... [详细]
  • PyQt5 QTextEdit:深入解析Python中多功能GUI库的应用与实现
    本文详细探讨了 PyQt5 中 QTextEdit 组件在 Python 多功能 GUI 库中的应用与实现。PyQt5 是 Qt 框架的 Python 绑定,提供了超过 620 个类和 6000 个函数及方法,广泛应用于跨平台应用程序开发。QTextEdit 作为其中的重要组件,支持丰富的文本编辑功能,如富文本格式、文本高亮和自定义样式等。PyQt5 的流行性不仅在于其强大的功能,还在于其易用性和灵活性,使其成为开发复杂用户界面的理想选择。 ... [详细]
  • 在Android开发中,通过调用系统内置的音频和视频播放功能,可以实现高效、便捷的多媒体处理。本文将详细介绍如何利用Android系统的媒体播放器组件,实现对音频和视频文件的播放控制,包括基本的播放、暂停、停止等操作,以及如何处理播放过程中的各种事件,确保应用的稳定性和用户体验。 ... [详细]
author-avatar
为什么要这2502928433
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有