flutter开发实战-go_router使用

flutter开发实战-go_router使用

在这里插入图片描述

一、go_router介绍与特性

go_router是一个Flutter的第三方声明式路由插件,使用路由器API提供一个方便的、基于url的API,用于在不同屏幕之间导航。可以定义URL模式、使用URL导航、处理深度链接以及许多其他与导航相关的场景。

GoRouter具有许多功能,使导航变得简单明了:

  • 使用模板语法解析路由路径和路由查询(query)参数;
  • 支持单个目标路由展示多个页面(子路由);
  • 重定向:可以基于应用状态跳转到不同的URL,比如用户没有登录时跳转到登录页;
  • 使用 StatefulShellRoute 可以支持嵌套的 Tab 导航;
  • 同时支持 Material 风格和 Cupertino 风格应用;
  • 兼容 Navigator API 。

二、引入go_router

根据自己需要的版本引入对应的版本,在pubspec.yaml加入

  go_router: ^8.2.0

稍后执行flutter pub get命令

三、go_router路由配置

引入插件后,我们需要配置MaterialApp.router的routerConfig

/// The route configuration.
final GoRouter _router = GoRouter(routes: <RouteBase>[GoRoute(path: '/',builder: (BuildContext context, GoRouterState state) {return const HomeScreen();},routes: <RouteBase>[GoRoute(path: 'details',builder: (BuildContext context, GoRouterState state) {return const DetailsScreen();},),],),],
);

配置MaterialApp.router

/// The main app.
class MyApp extends StatelessWidget {/// Constructs a [MyApp]const MyApp({super.key});@overrideWidget build(BuildContext context) {return MaterialApp.router(routerConfig: _router,);}
}

四、go_router路由跳转

如果跳转页面,可以使用content.go

context.go('/details')

4.1、路径参数

GoRouter 的每一个路由都通过 GoRoute对象来配置,可以通过路径参数进行传递相关参数到目标页面。例如路径comment/参数id

GoRoute(path: 'comment/:id',builder: (BuildContext context, GoRouterState state) {String? id = state.pathParameters['id'];print("id:${id}");// Get "id" param from URLreturn CommentScreen(id: id);},),

那么可以通过context.go(’/comment/55555’)传参数

ElevatedButton(onPressed: () => context.go('/comment/55555'),child: const Text('Go to the comment screen'),)

4.2、路径查询参数

可以获取路径的查询参数 URL 路径中的查询(query)参数,例如从/search?keyword=myname中获取search参数。

GoRoute(path: 'search',builder: (BuildContext context, GoRouterState state) {String? keyword = state.queryParameters['keyword'];print("keyword:${keyword}"); // Get "id" param from URLreturn SearchScreen(keyword: keyword);},),

传递参数context.go(’/search?keyword=myName’)目标页面可以得到参数myName

ElevatedButton(onPressed: () => context.go('/search?keyword=myName'),child: const Text('Go to the Search screen'),),

五、添加子路由

子路由,路由匹配支持多个页面,当一个新的页面在旧的页面之上展示时

GoRoute(path: 'details',builder: (BuildContext context, GoRouterState state) {return const DetailsScreen();},routes: <RouteBase>[// Add child routesGoRoute(path: 'sub-details',// NOTE: Don't need to specify "/" character for router’s parentsbuilder: (context, state) {return SubDetailsScreen();},),],),

可以通过context.go(’/details/sub-details’)来进行调用

ElevatedButton(onPressed: () => context.go('/details/sub-details'),child: const Text('Go to the SubDetails screen'),),

六、页面导航

go_router提供多种方式进行跳转

context.goNamed方式

ElevatedButton(onPressed: () => context.goNamed('/details'),child: const Text('Go to the Details screen'),),

七、路由重定向

go_router提供全局重定向,比如在没有登录的用户,需要跳转到登录页面.在 GoRouter 中,可以通过redirect 参数配置重定向.

redirect: (BuildContext context, GoRouterState state) {final isLogin = false;// your logic to check if user is authenticatedif (!isLogin) {return '/login';} else {return null; // return "null" to display the intended route without redirecting}}

八、错误处理(404页面)

go_router为MaterialApp 和CupertinoApp定义了默认的错误页面,也可以通过 errorBuilder 参数自定义错误页面。

errorBuilder: (BuildContext context,GoRouterState state,) {// ErrorPagereturn ErrorScreen();}

九、路由跳转监测

在flutter自带的会有NavigatorObserver,go_router页提供路由跳转监测功能

class MyNavigatorObserver extends NavigatorObserver {@overridevoid didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {print('did push route');}@overridevoid didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {print('did pop route');}
}

在observers中配置

GoRouter(observers: [MyNavigatorObserver()],
...
)

这里只是代码尝试了一下常用功能。还有一些转场动画、嵌套导航等等特性需要去尝试。
可以查看https://juejin.cn/post/7270343009790853172

注意:不同版本的代码有所不同。

测试的完整代码如下

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';void main() {runApp(const MyApp());
}class MyNavigatorObserver extends NavigatorObserver {@overridevoid didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {print('did push route');}@overridevoid didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {print('did pop route');}
}/// The route configuration.
final GoRouter _router = GoRouter(observers: [MyNavigatorObserver()],redirect: (BuildContext context, GoRouterState state) {final isLogin = false; // your logic to check if user is authenticatedif (!isLogin) {return '/login';} else {return null; // return "null" to display the intended route without redirecting}},errorBuilder: (BuildContext context,GoRouterState state,) {// ErrorPagereturn ErrorScreen();},routes: <RouteBase>[GoRoute(path: '/',builder: (BuildContext context, GoRouterState state) {return const HomeScreen();},routes: <RouteBase>[GoRoute(path: 'details',builder: (BuildContext context, GoRouterState state) {return const DetailsScreen();},routes: <RouteBase>[// Add child routesGoRoute(path: 'sub-details',// NOTE: Don't need to specify "/" character for router’s parentsbuilder: (context, state) {return SubDetailsScreen();},),],),GoRoute(path: 'comment/:id',builder: (BuildContext context, GoRouterState state) {String? id = state.pathParameters['id'];print("id:${id}"); // Get "id" param from URLreturn CommentScreen(id: id);},),GoRoute(path: 'search',builder: (BuildContext context, GoRouterState state) {String? keyword = state.queryParameters['keyword'];print("keyword:${keyword}"); // Get "id" param from URLreturn SearchScreen(keyword: keyword);},),],),],
);/// The main app.
class MyApp extends StatelessWidget {/// Constructs a [MyApp]const MyApp({super.key});@overrideWidget build(BuildContext context) {return MaterialApp.router(routerConfig: _router,);}
}/// The home screen
class HomeScreen extends StatelessWidget {/// Constructs a [HomeScreen]const HomeScreen({super.key});@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Screen')),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,crossAxisAlignment: CrossAxisAlignment.center,children: [ElevatedButton(onPressed: () => context.goNamed('/details'),child: const Text('Go to the Details screen'),),SizedBox(height: 30,),ElevatedButton(onPressed: () => context.go('/details/sub-details'),child: const Text('Go to the SubDetails screen'),),],),),);}
}/// The details screen
class DetailsScreen extends StatelessWidget {/// Constructs a [DetailsScreen]const DetailsScreen({super.key});@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Details Screen')),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,crossAxisAlignment: CrossAxisAlignment.center,children: [ElevatedButton(onPressed: () => context.go('/comment/55555'),child: const Text('Go to the comment screen'),),SizedBox(height: 30,),ElevatedButton(onPressed: () => context.go('/search?keyword=myName'),child: const Text('Go to the Search screen'),),],),),);}
}/// The details screen
class SubDetailsScreen extends StatelessWidget {/// Constructs a [SubDetailsScreen]const SubDetailsScreen({super.key});@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('SubDetailsScreen Screen')),body: Center(child: ElevatedButton(onPressed: () => context.go('/details'),child: const Text('Go back to the Details screen'),),),);}
}/// The details screen
class CommentScreen extends StatelessWidget {/// Constructs a [DetailsScreen]const CommentScreen({super.key, this.id});final String? id;@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('CommentScreen Screen')),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,crossAxisAlignment: CrossAxisAlignment.center,children: [Text("param id:${id}"),SizedBox(height: 30,),ElevatedButton(onPressed: () => context.go('/'),child: const Text('Go back to the Details screen'),),],)),);}
}/// The Search screen
class SearchScreen extends StatelessWidget {/// Constructs a [DetailsScreen]const SearchScreen({super.key, this.keyword});final String? keyword;@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('SearchScreen Screen')),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,crossAxisAlignment: CrossAxisAlignment.center,children: [Text("param keyword:${keyword}"),SizedBox(height: 30,),ElevatedButton(onPressed: () => context.go('/'),child: const Text('Go back to the details screen'),),],)),);}
}/// The Search screen
class ErrorScreen extends StatelessWidget {/// Constructs a [DetailsScreen]const ErrorScreen();@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('ErrorScreen Screen')),body: Center(child: Container(child: const Text('Error info'),),),);}
}

十、小结

flutter开发实战-go_router使用

学习记录,每天不停进步。

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

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

相关文章

【Spring Boot】Spring 的安全框架:Spring Security

Spring 的安全框架&#xff1a;Spring Security 1.Spring Security 初识1.1 核心概念1.2 认证和授权1.2.1 验证&#xff08;authentication&#xff09;1.2.2 授权&#xff08;authorization&#xff09; 1.3 模块 2.核心类2.1 Securitycontext2.2 SecurityContextHolder2.2.1 …

day51|99.岛屿数量, 100.岛屿的最大面积

99.岛屿数量 99. 岛屿数量 (kamacoder.com) DFS 思路没问题&#xff0c;内存超限了。 #include<iostream> #include<vector>using namespace std;int times 0;inline bool valid(int i, int j, const int &m, const int &n){return i > 0 &&am…

Python字符串处理技巧:一个小技巧竟然能省下你一半时间!

获取Pyhon及副业知识&#xff0c;关注公众号【软件测试圈】 效率翻倍的秘密&#xff1a;Python字符串操作的5个惊人技巧 在Python编程中&#xff0c;字符串处理在数据分析、Web开发、自动化脚本等多个领域都有广泛应用。Python提供了一系列强大的字符串处理函数&#xff0c;能够…

如何从零搭建一个动态网站

静态网站和动态网站的区别 静态网站和动态网站的本质区别在于内容是否在服务器端动态生成&#xff0c;以及是否有服务器端逻 辑处理用户请求和数据。 静态网站像是一本已经印刷好的书籍&#xff0c;而动态网站则像是根据读者需求即时编写和提供内容 的智能机器。 创建动态网…

前端工程化11-webpack常见插件

1、webpack的插件Plugin 刚才我们也讲解了下&#xff0c;我们对webpack路径的一个处理&#xff0c;处理的话包括别名的配置&#xff0c;模块是如何找到并加载的&#xff0c;总的来说到现在webpack这个配置到现在来说还是相当的麻烦的&#xff0c;但是目前来说我们讲的这些东西…

ssl证书过期,nginx更换证书以后仍然显示过期证书

记一次nginx部署异常 今天提示ssl证书过期了&#xff0c;然后重新申请了一个证书 反反复复折腾了一个上午&#xff0c;还更换了好几个平台&#xff0c;发现怎么更换都没用&#xff0c;百度上的解决方法都试过了&#xff0c;发现都没用&#xff0c;证书还是显示的原来那一个&…

前端工程化-vue项目创建

可以使用html、css、javascpript ,以及使用vue、axios等技术搭建前端页面&#xff0c;但效率低、结构乱。 实际前端开发&#xff1a; 前端工程化开发步骤&#xff1a; 一、环境准备 1.安装NodeJS2. 安装vue-cli 二、创建Vue项目 有两种方式创建&#xff0c;一般采用第二种图…

MMCV1.6.0之Runner/Hook/OptimizerHook(反向传播+参数更新)、Fp16OptimizerHook、自定义优化器与config设置

OptimizerHook 这段代码定义了一个名为 OptimizerHook 的类&#xff0c;它是一个用于优化器的自定义操作钩子。该钩子包含了一些用于梯度裁剪和检测异常参数的操作。这对于在深度学习训练过程中优化模型的性能和调试模型非常有用。 类的定义 OptimizerHook 类继承自 Hook&…

documents4j 将word转pdf文件,本地(Windows)测试没问题,部署到服务器(centos)报错

问题 报错如下&#xff1a; 代码 首先要保证你的Java代码没问题&#xff0c;可以参考下面代码 maven依赖 <!--documents4j--> <dependency><groupId>com.documents4j</groupId><artifactId>documents4j-local</artifactId><versi…

如果我是一名全能的工程师

今天的工作&#xff0c;让我深刻体会到为什么这两年&#xff0c;全栈这个词特别火&#xff0c;而且几乎每一家培训机构都在用全栈来推广他们的课程。 真正优秀的测试功能师&#xff0c;并不是单一的&#xff0c;能够从本身的功能里面找到多少BUG&#xff0c;或者说&#xff0c…

【SpringBoot】数据访问层Repository

数据访问层(Repository): 待办事项数据访问层(TodoRepository): Repository public interface TodoRepository extends JpaRepository<Todo,Long>{ List<Todo> findByUser(User,user); } 奖励数据访问层(RewardRepository): RewardRepository public inter…

解决mysql事件调度器重启服务后自动失效的问题

前段时间为通过mysql事件生成测试数据&#xff0c;今天发现数据在10:57后停止了CREATE EVENT IF NOT EXISTS insert_random_data ON SCHEDULE EVERY 10 SECOND DO INSERT INTO test (createtime, random_number) VALUES (NOW(), FLOOR(RAND() * 100));检查事件状态&#…

C++String类的手撕实现

目录 构造函数 提前准备工作&#xff1a; 有参构造 析构函数 c_str 无参构造&#xff1a; 无参和有参的结合 operater[]的实现 简易版的迭代器 begin end 原因&#xff1a; reserve 思想步骤 获取_capacity 和 _size 测试 push_back 思想步骤 append insert…

Vuex 介绍及示例

Vuex 是 Vue.js 的一个状态管理模式和库&#xff0c;用于管理 Vue 应用中的全局状态。它是专门为 Vue.js 应用设计的&#xff0c;充分利用了 Vue 的细粒度响应系统来高效地更新状态。以下是对 Vuex 的一些介绍和它的基本使用方法&#xff1a; 主要概念 State&#xff08;状态&…

平安养老险广西分公司开展7.8公益健步行活动

近日&#xff0c;平安养老保险股份有限公司&#xff08;以下简称“平安养老险”&#xff09;广西分公司在南宁邕江沿岸开展“7.8”公益健步行活动&#xff0c;在分公司班子的号召下&#xff0c;各部门内外勤员工均踊跃参与。 员工们沿途随手捡拾垃圾&#xff0c;传递积极、绿色…

就在刚刚,中国 IMO 奥数遗憾地失去了第一名的宝座,连续五年的统治地位被美国队所终结。

&#x1f431; 个人主页&#xff1a;TechCodeAI启航&#xff0c;公众号&#xff1a;TechCodeAI &#x1f64b;‍♂️ 作者简介&#xff1a;2020参加工作&#xff0c;专注于前端各领域技术&#xff0c;共同学习共同进步&#xff0c;一起加油呀&#xff01; &#x1f4ab; 优质专…

Vue3开源Tree组件研发:节点勾选支持v-model

自研Tree组件有两个原因&#xff1a;1. 目前开源UI对Tree组件的用户API不太友好&#xff0c;2. 提升Vue3组件自研能力。 目前已实现的功能见上面思维导图。想象Tree组件的一个使用场景&#xff1a;后台管理员通过Tree组件来完成用户角色授权&#xff0c;同时支持对权限进行新增…

Spring中使用到的设计模式及其源码分析

前言 众所周知&#xff0c;Spring框架是一个强大而灵活的开发框架。这不&#xff0c;上次的面试刚问到这些&#xff0c;没防住&#xff01;&#xff01;&#xff01;因此下来总结一下。这篇文章主要介绍Spring中使用到的设计模式&#xff0c;自己做个面试复盘&#xff0c;同时…

Spring Security 原理

Spring Security是一个功能强大且广泛使用的身份验证和授权框架&#xff0c;专为保护Java应用程序的安全性而设计。它提供了一套可配置的安全性规则和机制&#xff0c;用于对应用程序的资源进行访问控制和保护。以下是Spring Security的主要原理&#xff1a; 1. 过滤器链&…

富格林:防范虚假可信投资经验

富格林指出&#xff0c;现货黄金投资作为一种全球性的金融衍生品交易&#xff0c;吸引了无数投资者的目光。它不仅具备避险属性&#xff0c;还是资产配置中不可或缺的一部分。然而&#xff0c;要想在市场中防范虚假陷阱&#xff0c;投资者必须要掌握并且利用可信的投资经验。下…