go_router是Flutter官方开发的一个Flutter的声明式路由包。
go_router 包的目的是使用声明式路由来降低复杂性,无论您的目标平台是什么(移动、Web、桌面),处理来自 Android、iOS 和网络的深度和动态链接,以及其他一些导航相关的场景,同时希望提供易于使用的开发人员体验。
直接运行命令:
flutter pub add go_router
或者直接在 pubspec.yaml中添加依赖
dependencies:
go_router: ^5.0.0
然后导入就可以了
import 'package:go_router/go_router.dart';
使用:
class App extends StatelessWidget {
...
final _router = GoRouter(
routes: [],
);
...
Widget build(BuildContext context) {
return MaterialApp.router(
...
routerConfig: router, //add this
);
}
}
此时我们返回的就是MaterialApp.router , 只需要添加一行routerConfig即可。
final _router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => const Page1Screen(),
),
GoRoute(
path: '/page2',
builder: (context, state) => const Page2Screen(),
),
],
);
go_router 以 GoRouter 构造函数的一部分创建路由管理:
这种情况下,定义了两个路由,每个路由 path 都会匹配用户导航的位置。只有单个路由会被匹配,具体来说,就是某个路由的 path 会匹配整个位置(所以路由的列出顺序无关紧要)。
**path 匹配时忽略大小写,即使参数会保留大小写 **
除了 path 之外,每个路由会代表性地带有一个 builder 函数,该函数负责构建用来占据应用整个屏幕的组件。页面间会使用默认转换动画,取决于添加到组件树顶部的应用类型。例如,使用 MaterialApp 会让 go_router 使用 MaterialPage 的转换。
GoRoute的构造函数:
GoRoute({
required this.path, //路径
this.name,
this.builder, //负责构建屏幕的组件
this.pageBuilder,
this.parentNavigatorKey,
this.redirect,
List<RouteBase> routes = const <RouteBase>[],
})
虽然上面的代码片段中没有使用“路由状态”,但builder被传递了一个state对象,它是包含一些有用信息的 GoRouterState 类的实例:
| property | description | example 1 | example 2 |
|---|---|---|---|
| location | 完整路由的位置,包括查询参数 | /login?from=/family/f2 | /family/f2/person/p1 |
| subloc | 子路由的位置,不包含查询参数 | /login | /family/f2 |
| name | 路由名称 | login | /family |
| path` | 路由路径 | login | /family/:fid |
| fullpath | 该子路由的完整路径 | /login | /family/:fid |
| params | 从位置中提取的参数 | {} | {‘fid’: ‘f2’} |
| queryParams | 位置末尾的可选参数 | {‘from’: ‘/family/f1’} | {} |
| extra | 与导航一起传递的对象 | null | null |
| error | 与此子路由相关的错误 | ||
| pageKey | 该子路由的唯一Key | ValueKey(‘/login’) | ValueKey(‘/family/:fid’) |
其中最常用的一般是location,name,queryParams.
经常用location,name来跳转,通过queryParams来获取传递的参数.
路由的页面构建器
与builder类似,在实例化GoRoute对象时,必须提供builder与pageBuilder其中之一,返回要跳转的页面.
哎 , 那这时候有人就要问了,如果我都提供了会怎么样?
答案是会使用pageBuilder,builder无效.
PageBuilder允许开发人员设置路由的跳转动画:
pageBuilder: (_, GoRouterState state) => CustomTransitionPage(
child: const ListPage(),
transitionsBuilder: (BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) =>
FadeTransition(opacity: animation, child: child))
此路由的可选重定向功能
如果你想为特定路由(或子路由)做出重定向决定,可以通过将重定向函数传递给 GoRoute的构造函数来实现。
redirect: loginRedirect
...
FutureOr<String?> loginRedirect(BuildContext context, GoRouterState state) {
debugPrint('loginRedirect :${state.name}');
final loggingIn = state.subloc == 'login';
//如果没登录,并且当前不在登录页面,去登录 (并将本来想要跳转的页面传递到登录页)
if (!Constant.login && !loggingIn) {
return state.namedLocation(login, queryParams: {
'location': state.location,
'text': '未登录无法跳转到对应页面',
});
//return '/login?location=${state.location}';
}
return null;
}
我这里写了一个登录页面的重定向功能,因为我们经常有这样一个需求:有一个页面是需要登录之后才能访问的,如果没登录就跳转到登录页面.
最简单直观的实现方式就是在跳转之前,进行判断:
此时如果添加一个重定向功能,就不需要在跳转这个路由的时候进行是否已登录的判断,并且支持更多的条件判断.
我们就可以实现更复杂的逻辑了,在用户想跳转到这个路由的时候,可以根据不同的条件,跳转到不同的页面,也让代码去到了它该去的地方.
默认情况下,go_router 带有 MaterialApp 和 CupertinoApp 的默认错误页面,以及一个默认错误页面,那如果这两个你都不喜欢,可以通过设置 GoRouter 的 errorBuilder 参数来替换默认的错误屏幕:
class App extends StatelessWidget {
...
final _router = GoRouter(
...
errorBuilder: (context, state) => ErrorScreen(state.error),
);
}
同样的,errorBuilder也有一个对应的errorPageBuilder.
在出现以下情况时,会跳转到错误页面:
go_router提供了以下几种路由跳转方式:
通过location跳转:
context.go(String location, {Object? extra})
go方法需要提供"完整路由的位置,包括查询参数",
例如
context.go('/detail?id=b');
比如通过深度链接传来的URI格式的路由,以及推送之类的跳转,都推荐用到location来进行跳转.
然而当location比较复杂的时候,使用location来进行跳转 , 这不仅容易出错,而且应用程序的实际 URI 格式可能会随着时间而改变。当然,重定向有助于保持旧的 URI 格式正常工作,但你真的希望在代码中随意放置各种版本的位置 URI 吗?
通过name跳转:
context.goNamed(
String name, {
Map<String, String> params = const <String, String>{},
Map<String, dynamic> queryParams = const <String, dynamic>{},
Object? extra,
})
例如:
context.goNamed('detail',queryParams:{'id':'b'})
这种方式就比较符合我们的实际开发场景 , 我们不需要命名所有的路由,但是命名过的路由可以使用goNamed来直接进行导航.
另外,我们也可以通过context.namedLocation('name')来通过名字获取location.
queryParams参数是可选的,如果传递了这些参数,会在路由栈匹配的页面中的 state.queryParams 中,
GoRoute(
path: 'detail',
name: detail,
builder: (_, GoRouterState state) {
String? id = state.queryParams['id'];
return DetailPage(
id: id,
);
},
)
因为查询参数是可选的,未传递参数时,它们的值为 null 。
除了传递路径参数和查询参数之外,也可以传递附加的对象作为导航的一部分。例如:
context.go('detail',extra:object)
这个对象可以通过state.extra来获取.
如果想要简单的传递一个对象,使用extra还是很方便的.
但是, extra 对象会在用户使用浏览器的回退导航时丢失。
所以, extra 对象不建议用于 Flutter Web 应用。
go_router还提供了参数完全相同,但方法名不同的跳转方法 push.
二者区别:
for example:
路由: A:[B,C], 从B跳转到C
跳转前的路由栈: A-B
跳转后:
所以,定义路由线路的时候,一定要确定好路由的层级;跳转路由的时候,想好是使用go还是push.
RouteMatch是GoRoute的一个实例,并且包含当前位置的信息。
RouteMatch({
required this.route,
required this.subloc,
required this.fullpath,
required this.encodedParams,
required this.queryParams,
required this.queryParametersAll,
required this.extra,
required this.error,
this.pageKey,
})
可以看到, RouteMatc 的种的属性与 GoRouterState大同小异,可以通过RouteMatch来获取当前路由信息,那如何获取RouteMatch呢?
GoRouter.of(context).routerDelegate.currentConfiguration
该方法返回一个RouteMatchList,是当前的路由栈 ,
如果此时调用
debugPrint(
GoRouter.of(context).routerDelegate.currentConfiguration.last.subloc)
将会打印出最后一个,也就`当前子路由的位置.
也可以通过GoRouter.of(context).location来获取当前路由的完整路径.
我们经常有这么一个需求 , 在首页A页面,要跳到目标页B页面,但是B页面是登录后才可以进入的,未登录的情况下跳转到登录页.
所以我们的期望路由栈就是: 首页A --> 登录页 -->页面B
比方说 , 我们现在有一个app,帖子列表页不需要登录,帖子详情需要登录,未登录情况下,点击帖子跳转到登录页,已经登录的跳转到详情页.
你在帖子列表看到了一个美女,一点进去需要登录,等你登录完回到首页了, 列表还变了,这显然不符合你的需求,对吧.
你是希望登录之后,直接就进到帖子详情去看美女了.

那如果用go_router要怎么实现想要的效果呢?
因为B页面需要登录,所以对B页面设置一个重定向:
GoRoute(
path: 'detail',
name: detail,
builder: (_, GoRouterState state) {
String? id = state.queryParams['id'];
return DetailPage(
id: id,
);
},
redirect: loginRedirect),
FutureOr<String?> loginRedirect(BuildContext context, GoRouterState state) {
debugPrint('loginRedirect :${state.name}');
final loggingIn = state.subloc == 'login';
//如果没登录,并且当前不在登录页面,去登录 (并将本来想要跳转的页面传递到登录页)
if (!Constant.login && !loggingIn) {
return state.namedLocation(login, queryParams: {
'location': state.location,
'text': '未登录无法跳转到对应页面',
});
//return '/login?location=${state.location}';
}
return null;
}
在这个重定向方法中,如果未登录,会跳转到登录页面,并把本来要跳转的location传递到登录页,这样登录页在登录成功之后就可以用这个location进行跳转.
这个是我们登录页的路由设置,接收一个location参数:
GoRoute(
path: 'login',
name: login,
builder: (context, state) => LoginPage(
location: state.queryParams['location'],
text: state.queryParams['text'],
)),
在登录成功的时候,判断是否有location,如果有则进行跳转.
if (location != null) context.go('$location');
可以看到,我这里是使用的go方法跳转的, 前面提到过, 如果新路由不是旧路由的子路由,使用go跳转则会移除当前路由栈,也就是说
路由栈在登录之后就从 A–> 登录页 --> B 变成了 A --> B.
毕竟登录页是不需要在登录之后存在于路由栈中的.
有些时候,我们需要知道当前路由,跳转前的路由,或者是监听这个路由栈的变化,这时候,我们就需要有一个路由的监听.
GoRouter的构造方法中,有一个observers的参数, 它接收的是List<NavigatorObserver>?
所以我们可以自己实现一个NavigatorObserver,并重写相关生命周期的方法:
import 'package:flutter/material.dart';
class MyNavObserver extends NavigatorObserver {
void log(value) => debugPrint('MyNavObserver:$value');
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) => log(
'didPush: ${route.toString()}, previousRoute= ${previousRoute?.toString()}');
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) => log(
'didPop: ${route.toString()}, previousRoute= ${previousRoute?.toString()}');
void didRemove(Route<dynamic> route, Route<dynamic>? previousRoute) => log(
'didRemove: ${route.toString()}, previousRoute= ${previousRoute?.toString()}');
void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) => log(
'didReplace: new= ${newRoute?.toString()}, old= ${oldRoute?.toString()}');
void didStartUserGesture(
Route<dynamic> route,
Route<dynamic>? previousRoute,
) =>
log('didStartUserGesture: ${route.toString()}, '
'previousRoute= ${previousRoute?.toString()}');
void didStopUserGesture() => log('didStopUserGesture');
}
[1] example
目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称
@作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors 1、什么是behaviors 2、behaviors的工作方式 3、创建behavior 4、导入并使用behavior 5、behavior中所有可用的节点 6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors 1、什么是behaviorsbehaviors是小程序中,用于实现
遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg
ES一、简介1、ElasticStackES技术栈:ElasticSearch:存数据+搜索;QL;Kibana:Web可视化平台,分析。LogStash:日志收集,Log4j:产生日志;log.info(xxx)。。。。使用场景:metrics:指标监控…2、基本概念Index(索引)动词:保存(插入)名词:类似MySQL数据库,给数据Type(类型)已废弃,以前类似MySQL的表现在用索引对数据分类Document(文档)真正要保存的一个JSON数据{name:"tcx"}二、入门实战{"name":"DESKTOP-1TSVGKG","cluster_name":"elasticsear
在Railcasts上,我注意到一个非常有趣的功能“转到符号”窗口。它像Command-T一样工作,但显示当前文件中可用的类和方法。如何在vim中获取它? 最佳答案 尝试:helptags有各种程序和脚本可以生成标记文件。此外,标记文件格式非常简单,因此很容易将sed(1)或类似的脚本组合在一起,无论您使用何种语言,它们都可以生成标记文件。轻松获取标记文件(除了下载生成器之外)的关键在于格式化样式而不是实际解析语法。 关于ruby-on-rails-Textmate'Gotosymbol
文章目录1.任务背景2.任务目标3.相关知识点4.任务实操4.1安装配置JDK4.2启动FISCOBCOS4.3下载解压WeBASE-Front4.4拷贝sdk证书文件4.5启动节点4.6访问节点4.7检查运行状态5.任务总结1.任务背景FISCOBCOS其实是有控制台管理工具,用来对区块链系统进行各种管理操作。但是对于初学者来说,还是可视化界面更友好,本节就来介绍WeBASE管理平台,这是一款微众银行开源的自研区块链中间件平台,可以降低区块链使用的门槛,大幅提高区块链应用的开发效率。微众银行是腾讯牵头设立的民营银行,在国内民营银行里还是比较出名的。微众银行参与FISCOBCOS生态建设,一定
TCL脚本语言简介•TCL(ToolCommandLanguage)是一种解释执行的脚本语言(ScriptingLanguage),它提供了通用的编程能力:支持变量、过程和控制结构;同时TCL还拥有一个功能强大的固有的核心命令集。TCL经常被用于快速原型开发,脚本编程,GUI和测试等方面。•实际上包含了两个部分:一个语言和一个库。首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些互交程序如文本编辑器、调试器和shell。由于TCL的解释器是用C\C++语言的过程库实现的,因此在某种意义上我们又可以把TCL看作C库,这个库中有丰富的用于扩展TCL命令的C\C++过程和函数,所以,Tcl是
文章目录一、项目场景二、基本模块原理与调试方法分析——信源部分:三、信号处理部分和显示部分:四、基本的通信链路搭建:四、特殊模块:interpretedMATLABfunction:五、总结和坑点提醒一、项目场景 最近一个任务是使用simulink搭建一个MIMO串扰消除的链路,并用实际收到的数据进行测试,在搭建的过程中也遇到了不少的问题(当然这比vivado里面的debug好不知道多少倍)。准备趁着这个机会,先以一个很基本的通信链路对simulink基础和相关的debug方法进行总结。 在本篇中,主要记录simulink的基本原理和基本的SISO通信传输链路(QPSK方式),计划在下篇记
我为你们准备了一个简单的。我想要一个特色内容部分,其中排除了当前文章所以这可以通过delete_if使用MiddlemanBlog:但是我使用的是中间人代理,所以我无法访问current_article方法...我有一个YAML结构,其中包含以下模拟数据(以及其他数据),文件夹设置如下:data>site>caseStudy>RANDOM-ID423536.yaml(由CMS生成)在每个yaml文件中,您会发现如下内容::id:2k1YccJrQsKE2siSO6o6ac:title:Heyplace我的config.rb看起来像这样data.site.caseStudy.eachdo
目录一、ESP32简单介绍二、ESP32Wi-Fi模块介绍三、ESP32Wi-Fi编程模型四、ESP32Wi-Fi事件处理流程 五、ESP32Wi-Fi开发环境六、ESP32Wi-Fi具体代码七、ESP32Wi-Fi代码解读6.1主程序app_main7.2自定义代码wifi_init_sta()八、ESP32Wi-Fi连接验证8.1测试方法8.2服务器模拟工具sscom58.3测试代码8.4测试结果前言为了开发一款亚马逊物联网产品,开始入手ESP32模块。为了能够记录自己的学习过程,特记录如下操作过程。一、ESP32简单介绍ESP32是一套Wi-Fi(2.4GHz)和蓝牙(4.2)双模解决方