Flutter开发笔记:Flutter路由技术
- 文章信息 -Author: Jack Lee (jcLee95) Visit me at: jclee95.blog.csdn.netEmail: 291148484@163.com. Shenzhen ChinaAddress of this article:blog.csdn.net/qq_28550263…
【介绍】:本文介绍 Flutter 路由的原理,以及 go_router 模块的用法。
下一节:《 实战案例:使用go_router构建一个移动端音乐应用 》@[TOC](
目 录)
1. 概述
1.1 移动端路由简介
移动端应用开发中,路由技术是一个非常重要的组成部分。路由技术负责管理应用中各个页面之间的跳转、导航以及参数传递等关键功能。在移动端应用中,一个高效、易于维护的路由系统对于提高开发效率和用户体验具有重要意义。
1.2 本文内容导航
本文将对 Flutter 移动端应用开发中的路由技术进行详细讲解,内容涵盖以下几个方面:
- Flutter 路由基础知识,包括核心概念、基本操作以及传参等;
- 命名路由与动态路由的定义、使用以及对比;
go_router
模块的介绍,包括安装、配置、定义和注册路由等;- 使用
go_router
实现页面导航、处理深度链接、重定向等高级功能; - 路由守卫与路由过渡动画的实现;
- 通过实战案例,展示如何使用
go_router
构建一个完整的移动端应用。
通过学习本文,可以掌握 Flutter 路由技术的基本原理和实践方法,为开发高质量的移动端应用奠定坚实基础。
2. Flutter 路由基础
2.1 路由的核心:Route 和 Navigator
在 Flutter 中,路由技术的核心概念包括两个要素:Route 和 Navigator。
2.1.1 Route
Route 代表应用中的一个页面,它包含了页面的布局、逻辑以及生命周期等信息。在 Flutter 中,Route通常是一个继承自PageRoute
的类。
PageRoute
是一个抽象类,表示一个可以用于Navigator
的页面。它包含了页面的构建方法、过渡动画以及页面的生命周期回调等属性。在实际开发中,我们通常会使用以下两种PageRoute:MaterialPageRoute
或CupertinoPageRoute
:
-
MaterialPageRoute
:一个实现了Material Design风格的页面路由,它提供了平台特定的页面切换动画。在Android设备上,页面从底部滑入;在iOS设备上,页面从右侧滑入。如:// 使用MaterialPageRoute创建一个新页面 MaterialPageRoute(builder: (context) => NewPage());
-
CupertinoPageRoute
:一个实现了Cupertino风格(iOS风格)的页面路由,它提供了iOS平台特定的页面切换动画。如:// 使用CupertinoPageRoute创建一个新页面 CupertinoPageRoute(builder: (context) => NewPage());
2.1.2 Navigator(导航器)
在 Flutter 中,路由技术的另外一个核心概念是 Navigator。Navigator 是一个管理应用页面栈的组件,它负责处理页面之间的跳转、导航以及参数传递等操作。在 Flutter 中,Navigator类是一个关键的组件,它提供了一系列方法来实现页面间的导航
Navigator 是一个管理应用页面栈的组件,它负责处理页面之间的跳转、导航以及参数传递等操作。它通过一个栈结构来管理应用中的页面。当一个新页面被打开时,它会被压入栈顶;当一个页面被关闭时,它会从栈顶弹出。通过对栈的操作,Navigator实现了页面间的跳转和导航。
Navigator 类是一个关键的组件,它提供了一系列方法来实现页面间的导航。包括:
方法 | 描述 |
---|---|
push | 将一个新的页面压入栈顶,实现从当前页面跳转到新页面的功能。 |
pop | 将栈顶的页面弹出,实现从当前页面返回到上一个页面的功能。 |
replace | 将栈中的某个页面替换为新的页面。 |
pushAndRemoveUntil | 将一个新的页面压入栈顶,并移除栈中指定条件的页面。 |
pushNamed | 通过页面的名称进行跳转。 |
popAndPushNamed | 弹出当前页面并跳转到指定名称的页面。 |
为了在应用中使用Navigator
,我们需要将其添加到应用的组件树中。在实际开发中,我们通常会在MaterialApp 或 CupertinoApp 组件中配置 Navigator。
// 配置Navigator
MaterialApp(
home: HomePage(),
navigatorKey: GlobalKey<NavigatorState>(),
);
接下来,我们可以通过BuildContext来获取NavigatorState对象,进而进行页面间的导航操作。
// 使用push方法跳转到新页面
Navigator.of(context).push(MaterialPageRoute(builder: (context) => NewPage()));
// 使用pop方法返回上一个页面
Navigator.of(context).pop();
2.1.3 小结
本节通过了解Route和Navigator的核心概念、用法以及代码示例,您可以更好地理解和使用 Flutter 中的路由技术。在接下来的章节中,我们将继续深入讲解 Flutter 路由的其他知识点。
2.2 页面间导航的基本操作
在本节中,我们将介绍如何在 Flutter 应用中实现页面间的导航操作,包括页面的跳转、返回以及传递参数等。我们将分别讲解这些操作的原理、用法以及具体的代码示例。
2.2.1 页面跳转
页面跳转是指从当前页面导航到另一个页面的过程。在 Flutter 中,我们可以使用Navigator.push
方法将一个新的页面压入栈顶,从而实现页面跳转的功能。
页面跳转的主要步骤如下:
- 定义新页面的
Route
对象,如MaterialPageRoute
或CupertinoPageRoute
。 - 使用
Navigator.push
方法跳转到新页面。
例如:
// 定义新页面的Route对象
MaterialPageRoute newPageRoute = MaterialPageRoute(builder: (context) => NewPage());
// 使用Navigator.push方法跳转到新页面
Navigator.of(context).push(newPageRoute);
通过Navigator.push
方法,我们可以实现从当前页面跳转到新页面的功能。在实际开发中,我们通常会使用MaterialPageRoute
或CupertinoPageRoute
来创建新页面的Route对象。
2.2.2 页面返回
页面返回是指从当前页面返回到上一个页面的过程。在 Flutter 中,我们可以使用 Navigator.pop
方法将栈顶的页面弹出,从而实现页面返回的功能。
页面返回的主要步骤如下:
- 使用
Navigator.pop
方法返回上一个页面。
// 使用Navigator.pop方法返回上一个页面
Navigator.of(context).pop();
通过Navigator.pop
方法,我们可以实现从当前页面返回到上一个页面的功能。在实际开发中,我们通常会在页面的返回按钮或者手势操作中调用Navigator.pop
方法来实现页面返回。
2.2.3 页面替换
页面替换是指将栈顶的页面替换为一个新的页面。在 Flutter 中,我们可以使用Navigator.replace方法实现这个功能。
要使用页面替换功能,首先需要定义新页面的Route对象。然后调用Navigator.replace方法,传入BuildContext、新Route对象以及要替换的Route对象的标识符作为参数。
例如:
// 定义新页面的Route对象
MaterialPageRoute newPageRoute = MaterialPageRoute(builder: (context) => NewPage());
// 使用Navigator.replace方法替换栈顶的页面
Navigator.of(context).replace(
oldRoute: ModalRoute.of(context)!,
newRoute: newPageRoute,
);
2.2.4 页面移除
页面移除是指将指定的页面从导航堆栈中移除。在 Flutter 中,我们可以使用 Navigator.removeRoute 方法实现这个功能。
要使用页面移除功能,首先需要获取要移除的页面的Route对象。然后调用 Navigator.removeRoute 方法,传入 BuildContext 和要移除的Route对象作为参数。
以下是一个具体的代码示例:
// 获取要移除的页面的Route对象
Route routeToRemove = ModalRoute.of(context)!;
// 使用Navigator.removeRoute方法移除指定页面
Navigator.of(context).removeRoute(routeToRemove);
2.2.5 小结
本节详细讲解了 Flutter 中页面间导航的基本操作,包括页面跳转、页面返回、页面替换和页面移除等。通过了解这些操作的原理、用法和代码示例,您可以更好地理解和使用 Flutter 中的页面间导航操作。在接下来的章节中,我们将继续深入讲解 Flutter 路由的其他知识点。
2.3 路由传参与接收参数
在本节中,我们将介绍如何在 Flutter 应用中实现路由传参以及接收参数的方法。我们将按照原理、用法和代码示例的顺序,分别讲解这些操作的具体内容。
2.3.1 路由传参
路由传参是指在跳转到新页面时,将参数传递给新页面,以便新页面根据参数进行相应的操作。在 Flutter 中,我们可以在创建新页面的Route
对象时,将参数传递给新页面的构造函数。
以下是一个具体的代码示例:
class NewPage extends StatelessWidget {
final String data;
NewPage({required this.data});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('New Page'),
),
body: Center(
child: Text('Data received: $data'),
),
);
}
}
// 在跳转时传递参数
MaterialPageRoute newPageRoute = MaterialPageRoute(builder: (context) => NewPage(data: 'Hello, Flutter!'));
Navigator.of(context).push(newPageRoute);
2.3.2 接收参数
接收参数是指在新页面中获取传递过来的参数,并根据参数进行相应的操作。在 Flutter 中,我们可以在新页面的构造函数中接收传递过来的参数。
以下是一个具体的代码示例:
class NewPage extends StatelessWidget {
final String data;
NewPage({required this.data});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('New Page'),
),
body: Center(
child: Text('Data received: $data'),
),
);
}
}
2.3.3 返回参数
返回参数是指在返回上一个页面时,将参数传递回上一个页面。在 Flutter 中,我们可以在调用Navigator.pop
方法时,将参数作为方法的第二个参数传递。
以下是一个具体的代码示例:
// 在返回上一个页面时传递参数
Navigator.of(context).pop('Hello, Flutter!');
2.3.4 接收返回参数
接收返回参数是指在上一个页面中获取返回的参数,并根据参数进行相应的操作。在 Flutter 中,我们可以在调用Navigator.push
方法时,通过then
方法获取返回的参数。
以下是一个具体的代码示例:
MaterialPageRoute newPageRoute = MaterialPageRoute(builder: (context) => NewPage());
Navigator.of(context).push(newPageRoute).then((result) {
print('Data returned: $result');
});
2.3.5 小结
本节详细讲解了 Flutter 中路由传参与接收参数的方法,包括路由传参、接收参数、返回参数和接收返回参数等。通过了解这些操作的原理、用法和代码示例,您可以更好地理解和使用 Flutter 中的路由传参与接收参数。在接下来的章节中,我们将继续深入讲解 Flutter 路由的其他知识点。
3. 命名路由与动态路由
3.1 命名路由的定义与使用
在本节中,我们将介绍如何在 Flutter 应用中定义和使用命名路由(静态路由)。我们将按照原理、用法和代码示例的顺序,分别讲解这些操作的具体内容。
3.1.1 命名路由的定义
命名路由是指为每个路由分配一个名称,以便在进行页面跳转时使用名称来引用路由。在 Flutter 中,我们可以在MaterialApp
或CupertinoApp
的routes
属性中定义命名路由。
以下是一个具体的代码示例:
MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => HomePage(),
'/new': (context) => NewPage(),
},
);
3.1.2 使用命名路由进行页面跳转
使用命名路由进行页面跳转是指在跳转到新页面时,通过路由名称来引用新页面。在 Flutter 中,我们可以使用Navigator.pushNamed
方法进行页面跳转,传入BuildContext和路由名称作为参数。
以下是一个具体的代码示例:
// 使用Navigator.pushNamed方法跳转到新页面
Navigator.of(context).pushNamed('/new');
3.1.3 使用命名路由进行页面返回
使用命名路由进行页面返回是指在返回上一个页面时,通过路由名称来引用上一个页面。在 Flutter 中,我们可以使用Navigator.popAndPushNamed
方法进行页面返回,传入BuildContext和路由名称作为参数。
以下是一个具体的代码示例:
// 使用Navigator.popAndPushNamed方法返回上一个页面
Navigator.of(context).popAndPushNamed('/');
3.1.4 使用命名路由进行页面替换
使用命名路由进行页面替换是指在替换栈顶的页面时,通过路由名称来引用新页面。在 Flutter 中,我们可以使用Navigator.pushReplacementNamed
方法进行页面替换,传入BuildContext和路由名称作为参数。
以下是一个具体的代码示例:
// 使用Navigator.pushReplacementNamed方法替换栈顶的页面
Navigator.of(context).pushReplacementNamed('/new');
3.1.5 小结
本节详细讲解了命名路由(静态路由)的定义与使用,包括命名路由的定义、使用命名路由进行页面跳转、页面返回和页面替换等。通过了解这些操作的原理、用法和代码示例,您可以更好地理解和使用 Flutter 中的命名路由(静态路由)。在接下来的章节中,我们将继续深入讲解 Flutter 路由的其他知识点,包括动态路由的定义与使用。
3.2 动态路由的定义与使用
在本节中,我们将介绍如何在 Flutter 应用中定义和使用动态路由。我们将按照原理、用法和代码示例的顺序,分别讲解这些操作的具体内容。
3.2.1 动态路由的定义
动态路由是指在进行页面跳转时,根据传入的参数生成路由。与命名路由相比,动态路由更加灵活,可以根据需要生成不同的路由。在 Flutter 中,我们可以通过MaterialApp
或CupertinoApp
的onGenerateRoute
属性来定义动态路由。
以下是一个具体的代码示例:
MaterialApp(
initialRoute: '/',
onGenerateRoute: (settings) {
switch (settings.name) {
case '/':
return MaterialPageRoute(builder: (context) => HomePage());
case '/new':
final String data = settings.arguments as String;
return MaterialPageRoute(builder: (context) => NewPage(data: data));
default:
return MaterialPageRoute(builder: (context) => NotFoundPage());
}
},
);
3.2.2 使用动态路由进行页面跳转
使用动态路由进行页面跳转是指在跳转到新页面时,通过传递参数来生成新页面的路由。在 Flutter 中,我们可以使用Navigator.pushNamed
方法进行页面跳转,传入BuildContext、路由名称和参数作为参数。
以下是一个具体的代码示例:
// 使用Navigator.pushNamed方法跳转到新页面,并传递参数
Navigator.of(context).pushNamed('/new', arguments: 'Hello, Flutter!');
3.2.3 使用动态路由进行页面返回
使用动态路由进行页面返回是指在返回上一个页面时,通过传递参数来生成上一个页面的路由。在 Flutter 中,我们可以使用Navigator.popAndPushNamed
方法进行页面返回,传入BuildContext、路由名称和参数作为参数。
以下是一个具体的代码示例:
// 使用Navigator.popAndPushNamed方法返回上一个页面,并传递参数
Navigator.of(context).popAndPushNamed('/', arguments: 'Hello, Flutter!');
3.2.4 使用动态路由进行页面替换
使用动态路由进行页面替换是指在替换栈顶的页面时,通过传递参数来生成新页面的路由。在 Flutter 中,我们可以使用Navigator.pushReplacementNamed
方法进行页面替换,传入BuildContext、路由名称和参数作为参数。
以下是一个具体的代码示例:
// 使用Navigator.pushReplacementNamed方法替换栈顶的页面,并传递参数
Navigator.of(context).pushReplacementNamed('/new', arguments: 'Hello, Flutter!');
3.1.5 小结
本节详细讲解了动态路由的定义与使用,包括动态路由的定义、使用动态路由进行页面跳转、页面返回和页面替换等。通过了解这些操作的原理、用法和代码示例,您可以更好地理解和使用 Flutter 中的动态路由。在接下来的章节中,我们将继续深入讲解 Flutter 路由的其他知识点,以帮助您更好地掌握 Flutter 路由的使用方法。
3.3 命名路由 与 动态路由 的比较
在本节中,我们将对比命名路由和动态路由的特点,以及它们各自适用的场景。通过对比分析,您将更好地理解这两种路由方式的差异,从而在实际项目中选择更合适的路由方式。
3.3.1 命名路由与动态路由的对比
下面是命名路由和动态路由的对比:
- 定义方式:命名路由通过
MaterialApp
或CupertinoApp
的routes
属性定义,而动态路由通过onGenerateRoute
属性定义。 - 参数传递:命名路由在进行页面跳转时,需要将参数定义在路由名称中,而动态路由可以通过
arguments
属性直接传递参数。 - 灵活性:动态路由相比于命名路由更加灵活,因为它可以根据传入的参数动态生成路由,而命名路由需要预先定义好所有的路由名称。
- 易用性:对于简单的页面跳转,命名路由更加易用,因为它只需要预先定义好路由名称即可。然而,在需要根据参数动态生成路由的场景下,动态路由更加方便。
3.3.2 适用场景
下面是命名路由和动态路由各自适用的场景:
- 命名路由:适用于简单的页面跳转,无需根据参数动态生成路由的场景。例如,从主页跳转到关于页面,或从商品列表页跳转到商品详情页等。
- 动态路由:适用于需要根据参数动态生成路由的场景。例如,从用户列表页跳转到用户详情页时,需要根据用户ID生成不同的用户详情页面;或者在一个新闻应用中,根据不同的新闻类别生成不同的新闻列表页面等。
3.3.3 小结
本节通过对比命名路由和动态路由的特点,以及它们各自适用的场景,帮助您更好地理解这两种路由方式的差异。在实际项目中,您可以根据具体需求选择合适的路由方式。总的来说,对于简单的页面跳转,命名路由更加易用;而在需要根据参数动态生成路由的场景下,动态路由更加方便。
在接下来的章节中,我们将继续深入讲解 Flutter 路由的其他知识点,以帮助您更好地掌握 Flutter 路由的使用方法。
4. go_router 模块介绍
4.1 go_router 模块的特点
在本节中,我们将介绍 go_router
模块的优势与特点。go_router
是一个用于 Flutter 的路由库,它提供了一种简洁、强大且易于维护的路由管理方式。
解go_router
模块有以下优势:
- 类型安全:
go_router
模块支持类型安全的路由参数传递,可以有效地减少因参数类型错误而导致的运行时错误。 - 代码简洁:
go_router
模块采用声明式的编程方式,可以让您的代码更加简洁、易读和易于维护。 - 功能丰富:
go_router
模块提供了多种路由功能,包括命名路由、动态路由、路由守卫、路由重定向等,可以满足各种复杂场景的需求。 - 与现有框架兼容:
go_router
模块与其他 Flutter 框架(如Provider、Riverpod、GetX等)兼容良好,可以方便地集成到您的项目中。
从功能上上看, go_router
模块有以下特点:
- 命名路由:
go_router
模块支持命名路由,可以让您更方便地管理和跳转到指定页面。 - 动态路由:
go_router
模块支持动态路由,可以根据传入的参数生成不同的路由,适用于需要根据参数动态生成路由的场景。 - 路由守卫:
go_router
模块支持路由守卫,可以在路由跳转过程中添加条件判断,例如进行身份验证、权限检查等。 - 路由重定向:
go_router
模块支持路由重定向,可以根据需要将用户从一个路由重定向到另一个路由。 - 浏览器支持:
go_router
模块支持 Flutter Web应用,可以在浏览器中使用URL进行页面跳转。
4.2 安装与配置 go_router 模块
在本节中,我们将介绍如何安装和配置go_router
模块。通过以下步骤,您可以将go_router
模块添加到您的 Flutter 项目中,并进行基本的配置。
4.2.1 添加依赖
首先,在您的 Flutter 项目的pubspec.yaml
文件中,添加go_router
模块的依赖。您可以在pub.dev上查找到go_router
模块的最新版本。以下是一个添加依赖的示例:
dependencies:
flutter:
sdk: flutter
go_router: ^2.4.2
添加依赖后,运行flutter pub get
命令以下载并安装go_router
模块。
4.2.2 导入 go_router 模块
在需要使用go_router
模块的文件中,导入go_router
模块:
import 'package:go_router/go_router.dart';
4.2.3 定义路由
接下来,定义您的项目中需要使用的路由。创建一个GoRoute
对象的列表,每个GoRoute
对象代表一个路由。以下是一个定义路由的示例:
final goRoutes = [
GoRoute(
path: '/',
pageBuilder: (context, state) {
return MaterialPage(child: HomePage());
}),
GoRoute(
path: '/details/:id',
pageBuilder: (context, state) {
final id = state.params['id'];
return MaterialPage(child: DetailsPage(id: id));
}),
];
在此示例中,我们定义了两个路由:一个是主页(/
),另一个是详情页(/details/:id
)。详情页的路由路径包含一个动态参数id
。
4.2.4 初始化 GoRouter 对象
创建一个GoRouter
对象,并将之前定义的路由列表传递给它:
final goRouter = GoRouter(routes: goRoutes);
4.2.5 配置 MaterialApp 或 CupertinoApp
将GoRouter
对象传递给MaterialApp.router
或CupertinoApp.router
属性。以下是一个配置MaterialApp
的示例:
MaterialApp.router(
routerDelegate: goRouter.routerDelegate,
routeInformationParser: goRouter.routeInformationParser,
);
4.2.6 小结
本节介绍了如何安装和配置go_router
模块。通过添加依赖、导入模块、定义路由、初始化GoRouter对象和配置MaterialApp或CupertinoApp,您可以将go_router
模块集成到您的 Flutter 项目中。在接下来的章节中,我们将继续深入讲解go_router
模块的使用方法,包括如何进行页面跳转、传递参数、使用路由守卫等。
4.3 定义和注册路由
在本节中,我们将详细介绍如何定义和注册go_router
模块中的路由。通过以下步骤,您可以在您的 Flutter 项目中创建和使用go_router
模块的路由。
4.3.1 定义路由
如前文所述,您需要创建一个GoRoute
对象的列表来定义路由。每个GoRoute
对象都需要包含以下属性:
path
:路由路径,可以包含动态参数(如/details/:id
)。pageBuilder
:页面构建器,接收一个BuildContext和GoRouterState对象,返回一个Page对象。您可以在此处创建并返回您的页面(如MaterialPage
、CupertinoPage
等)。
以下是一个定义路由的示例:
final goRoutes = [
GoRoute(
path: '/',
pageBuilder: (context, state) {
return MaterialPage(child: HomePage());
}),
GoRoute(
path: '/details/:id',
pageBuilder: (context, state) {
final id = state.params['id'];
return MaterialPage(child: DetailsPage(id: id));
}),
];
4.3.2 注册路由
在定义了路由列表后,您需要创建一个GoRouter
对象,并将路由列表传递给它。这样,您的路由就会被注册到go_router
模块中:
final goRouter = GoRouter(routes: goRoutes);
4.3.3 使用命名路由
为了更方便地管理和使用路由,您可以为每个路由添加一个name
属性。这样,您可以通过路由名称来跳转到指定页面,而无需记住路由路径。以下是一个使用命名路由的示例:
final goRoutes = [
GoRoute(
path: '/',
name: 'home',
pageBuilder: (context, state) {
return MaterialPage(child: HomePage());
}),
GoRoute(
path: '/details/:id',
name: 'details',
pageBuilder: (context, state) {
final id = state.params['id'];
return MaterialPage(child: DetailsPage(id: id));
}),
];
在为路由添加了名称后,您可以使用GoRouter
对象的goNamed
方法来跳转到指定页面:
goRouter.goNamed(context, 'details', params: {'id': '123'});
4.3.4 小结
本节详细介绍了如何定义和注册go_router
模块中的路由。通过创建GoRoute
对象的列表、为路由添加名称和使用GoRouter
对象的方法,您可以在您的 Flutter 项目中轻松地创建和使用go_router
模块的路由。在接下来的章节中,我们将继续深入讲解go_router
模块的使用方法,包括如何进行页面跳转、传递参数、使用路由守卫等。
5. 使用 go_router 实现页面导航
5.1 基于URL的导航
在本节中,我们将介绍如何使用go_router
模块实现基于URL的页面导航。通过以下步骤,您可以在您的 Flutter 项目中使用go_router
模块进行页面跳转和参数传递。
5.1.1 页面跳转
使用go_router
模块进行页面跳转非常简单。您只需调用GoRouter
对象的go
方法,并传入当前的BuildContext
和目标页面的URL。以下是一个页面跳转的示例:
goRouter.go(context, '/details/123');
在此示例中,我们跳转到了/details/123
路径对应的页面。
5.1.2 传递参数
go_router
模块允许您通过URL直接传递参数给目标页面。在定义路由时,您可以在路径中添加动态参数,如/details/:id
。然后,在页面跳转时,将参数值直接填充到路径中,如/details/123
。
在目标页面的pageBuilder
方法中,您可以通过GoRouterState
对象的params
属性获取传递的参数值。以下是一个获取参数值的示例:
final id = state.params['id'];
5.1.3 使用命名路由
如前文所述,您可以为路由添加名称,以便更方便地进行页面跳转。在为路由添加了名称后,您可以使用GoRouter
对象的goNamed
方法来跳转到指定页面,并传递参数:
goRouter.goNamed(context, 'details', params: {'id': '123'});
在此示例中,我们跳转到了名称为details
的路由对应的页面,并传递了一个id
参数。
5.1.4 小结
本节介绍了如何使用 go_router
模块实现基于 URL 的页面导航。通过调用GoRouter
对象的go
或goNamed
方法,您可以在您的 Flutter 项目中轻松地进行页面跳转和参数传递。在接下来的章节中,我们将继续深入讲解 go_router
模块的使用方法,包括如何使用路由守卫、处理页面过渡动画等。
5.2 使用GoRouter类进行导航
在本节中,我们将介绍如何使用GoRouter
类提供的方法进行页面导航。GoRouter
类提供了一系列便捷的方法,使得在 Flutter 项目中进行页面跳转和参数传递变得更加简单。
5.2.1 使用 go 方法进行导航
GoRouter
类的go
方法允许您通过URL进行页面导航。您只需传入当前的BuildContext
和目标页面的URL即可。以下是一个使用go
方法进行页面跳转的示例:
goRouter.go(context, '/details/123');
在此示例中,我们跳转到了/details/123
路径对应的页面。
5.2.2 使用 goNamed 方法进行导航
GoRouter
类的goNamed
方法允许您通过路由名称进行页面导航。您需要传入当前的BuildContext
、目标页面的路由名称以及一个可选的参数映射。以下是一个使用goNamed
方法进行页面跳转的示例:
goRouter.goNamed(context, 'details', params: {'id': '123'});
在此示例中,我们跳转到了名称为details
的路由对应的页面,并传递了一个id
参数。
5.2.3 使用 goBack 方法返回上一页
GoRouter
类的goBack
方法允许您返回上一页。您只需传入当前的BuildContext
即可。以下是一个使用goBack
方法返回上一页的示例:
goRouter.goBack(context);
5.2.4 使用 goTo 方法跳转到指定页面
GoRouter
类的goTo
方法允许您跳转到指定页面。您需要传入当前的BuildContext
、一个GoRouteMatch
对象以及一个可选的参数映射。以下是一个使用goTo
方法跳转到指定页面的示例:
final match = goRouter.match('/details/123');
goRouter.goTo(context, match, params: {'id': '123'});
在此示例中,我们首先使用match
方法获取与URL对应的GoRouteMatch
对象,然后使用goTo
方法跳转到指定页面,并传递了一个id
参数。
5.2.5 小结
本节介绍了如何使用GoRouter
类进行页面导航。通过调用GoRouter
类的go
、goNamed
、goBack
和goTo
方法,您可以在您的 Flutter 项目中轻松地进行页面跳转和参数传递。在接下来的章节中,我们将继续深入讲解go_router
模块的使用方法,包括如何使用路由守卫、处理页面过渡动画等。
5.3 页面间传参与接收参数
在使用go_router
进行页面导航时,您可能需要在页面间传递参数。本节将介绍如何在使用go_router
进行页面跳转时传递参数,并在目标页面中接收这些参数。
5.3.1 在页面跳转时传递参数
要在页面跳转时传递参数,您可以在URL中直接添加动态参数,或者使用命名路由时通过params
参数传递。以下是两种传递参数的示例:
通过URL传递参数:
goRouter.go(context, '/details/123');
在此示例中,我们将123
作为参数传递给了/details/123
路径对应的页面。
通过命名路由传递参数:
goRouter.goNamed(context, 'details', params: {'id': '123'});
在此示例中,我们使用命名路由跳转到details
页面,并通过params
参数传递了一个id
参数。
5.3.2 在目标页面接收参数
要在目标页面接收参数,您可以在pageBuilder
方法中通过GoRouterState
对象的params
属性获取传递的参数值。以下是一个在目标页面接收参数的示例:
final id = state.params['id'];
在此示例中,我们从state.params
中获取了名为id
的参数值。
5.3.3 使用类型安全的方式传递参数
为了避免在传递参数时出现类型错误,您可以使用GoRoute
的paramsBuilder
属性定义一个类型安全的参数构建器。以下是一个定义类型安全参数构建器的示例:
GoRoute(
path: '/details/:id',
pageBuilder: (context, state) {
final id = state.params['id'];
return MaterialPage(child: DetailsPage(id: id));
},
paramsBuilder: (params) {
final id = params['id'];
if (id == null) throw Exception('id is required');
return {'id': int.parse(id)};
},
)
在此示例中,我们为GoRoute
定义了一个paramsBuilder
,它将id
参数从字符串转换为整数。这样,在pageBuilder
中,我们可以直接使用类型安全的id
参数。
5.3.5 小结
本节介绍了如何在使用go_router
进行页面导航时传递参数以及在目标页面中接收这些参数。通过在URL中添加动态参数或者使用命名路由时传递params
参数,您可以轻松地在页面间传递参数。同时,您还可以使用GoRoute
的paramsBuilder
属性定义类型安全的参数构建器,以避免在传递参数时出现类型错误。在接下来的章节中,我们将继续深入讲解go_router
模块的使用方法,包括如何使用路由守卫、处理页面过渡动画等。
6. 处理深度链接与重定向
6.1 深度链接的概念与应用
深度链接(Deep Linking)是一种允许用户直接打开应用内特定页面的技术。通过深度链接,您可以将用户从网页、广告、电子邮件或其他应用直接导航到您的应用的特定页面,而不仅仅是应用的主页面。这有助于提高用户体验,增加用户参与度,并提高应用的转化率。
在本节中,我们将介绍深度链接的概念,以及如何在使用go_router
模块的 Flutter 应用中处理深度链接。
6.1.1 深度链接的类型
深度链接主要分为两种类型:
- 普通深度链接(Standard Deep Links):这种类型的深度链接使用标准的URL格式,例如
https://example.com/details/123
。当用户点击此类链接时,应用会尝试打开对应的页面。如果应用尚未安装,用户将被重定向到应用商店。 - 通用链接(Universal Links):通用链接是一种特殊类型的深度链接,它允许您为一个URL创建一个唯一的关联。当用户点击通用链接时,系统会根据关联信息自动判断是否打开应用或者网页。通用链接在iOS和Android平台上分别称为“通用链接(Universal Links)”和“应用链接(App Links)”。
6.1.2 在 Flutter 应用中处理深度链接
要在 Flutter 应用中处理深度链接,您需要使用uni_links
库。首先,在pubspec.yaml
文件中添加uni_links
库的依赖项:
dependencies:
uni_links: ^0.5.1
然后,您需要在应用的入口点(通常是main
函数)监听深度链接事件。以下是一个监听深度链接事件的示例:
import 'package:uni_links/uni_links.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 监听深度链接事件
StreamSubscription _sub = getUriLinksStream().listen((Uri uri) {
// 处理深度链接
print('Received deep link: $uri');
}, onError: (Object err) {
print('Failed to handle deep link: $err');
});
runApp(MyApp());
}
在此示例中,我们使用getUriLinksStream
函数获取深度链接事件流,并监听该流以处理深度链接。
6.1.3 在 go_router 中处理深度链接
要在使用 go_router
的 Flutter 应用中处理深度链接,您需要将深度链接的 URL 映射到应用内的页面。以下是一个在 go_router
中处理深度链接的示例:
final goRouter = GoRouter(
routes: [
GoRoute(
path: '/',
pageBuilder: (context, state) => MaterialPage(child: HomePage()),
),
GoRoute(
path: '/details/:id',
pageBuilder: (context, state) {
final id = state.params['id'];
return MaterialPage(child: DetailsPage(id: id));
},
),
],
redirect: (state) {
// 从深度链接中获取参数
final uri = Uri.parse(state.location);
// 根据深度链接的URL映射到应用内的页面
if (uri.path == '/details') {
final id = uri.queryParameters['id'];
return '/details/$id';
}
},
);
在此示例中,我们为GoRouter
定义了一个redirect
函数,该函数根据深度链接的URL将用户重定向到应用内的页面。
6.1.4 小结
本节介绍了深度链接的概念,以及如何在使用go_router
模块的 Flutter 应用中处理深度链接。深度链接是一种允许用户直接打开应用内特定页面的技术,有助于提高用户体验,增加用户参与度,并提高应用的转化率。在接下来的章节中,我们将继续讲解如何在go_router
中处理重定向,以便更好地管理应用的页面跳转逻辑。
6.2 使用 go_router 处理深度链接
在上一节中,我们介绍了深度链接的概念以及如何在 Flutter 应用中处理深度链接。本节将重点介绍如何在使用 go_router
模块的应用中处理深度链接。
6.2.1 安装并配置 uni_links 库
首先,我们需要安装uni_links
库来处理深度链接。在pubspec.yaml
文件中添加uni_links
库的依赖项:
dependencies:
uni_links: ^0.5.1
接下来,我们需要在应用的入口点(通常是main
函数)监听深度链接事件。以下是一个监听深度链接事件的示例:
import 'package:uni_links/uni_links.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 监听深度链接事件
StreamSubscription _sub = getUriLinksStream().listen((Uri uri) {
// 处理深度链接
print('Received deep link: $uri');
}, onError: (Object err) {
print('Failed to handle deep link: $err');
});
runApp(MyApp());
}
6.2.2 定义 go_router 的路由
为了处理深度链接,我们需要在go_router
中定义与深度链接相关的路由。以下是一个定义了两个路由的示例:
final goRouter = GoRouter(
routes: [
GoRoute(
path: '/',
pageBuilder: (context, state) => MaterialPage(child: HomePage()),
),
GoRoute(
path: '/details/:id',
pageBuilder: (context, state) {
final id = state.params['id'];
return MaterialPage(child: DetailsPage(id: id));
},
),
],
);
在此示例中,我们定义了两个路由:主页(/
)和详情页(/details/:id
)。详情页的路由包含一个名为id
的参数,该参数将从深度链接的URL中提取。
6.2.3 在go_router
中处理深度链接
要在go_router
中处理深度链接,我们需要定义一个redirect
函数。以下是一个在go_router
中处理深度链接的示例:
final goRouter = GoRouter(
routes: [
// ...路由定义...
],
redirect: (state) {
// 从深度链接中获取参数
final uri = Uri.parse(state.location);
// 根据深度链接的URL映射到应用内的页面
if (uri.path == '/details') {
final id = uri.queryParameters['id'];
return '/details/$id';
}
},
);
在此示例中,我们为GoRouter
定义了一个redirect
函数,该函数根据深度链接的URL将用户重定向到应用内的页面。
6.2.4 在应用中使用go_router
导航
现在我们已经为go_router
配置了深度链接处理,我们可以在应用中使用go_router
的导航功能。以下是一个使用go_router
导航到详情页的示例:
void _onDetailsButtonPressed(BuildContext context) {
final goRouter = GoRouter.of(context);
goRouter.go('/details/42');
}
在此示例中,我们使用GoRouter.of
函数获取应用的GoRouter
实例,然后调用go
方法导航到详情页。
6.2.5 小结
本节介绍了如何在使用 go_router
模块的 Flutter 应用中处理深度链接。我们首先安装并配置了uni_links
库,然后定义了与深度链接相关的路由。接下来,我们在 go_router
中定义了一个redirect
函数来处理深度链接,最后在应用中使用 go_router
进行导航。
通过使用 go_router
处理深度链接,您可以为用户提供更好的体验,从而提高用户参与度和应用转化率。
6.3 实现重定向
在本节中,我们将介绍如何在使用go_router
模块的 Flutter 应用中实现重定向。重定向是一种在用户尝试访问某个页面时将其引导到另一个页面的方法。这在许多场景中非常有用,例如权限控制、条件渲染等。
6.3.1 定义重定向函数
要实现重定向,我们需要在GoRouter
中定义一个redirect
函数。以下是一个简单的重定向函数示例,该函数将用户从/old
路径重定向到/new
路径:
final goRouter = GoRouter(
routes: [
// ...路由定义...
],
redirect: (state) {
if (state.location == '/old') {
return '/new';
}
},
);
在此示例中,我们为GoRouter
定义了一个redirect
函数,该函数根据state.location
的值将用户重定向到不同的页面。
6.3.2 实现基于权限的重定向
在实际应用中,我们可能需要根据用户的权限来决定是否允许访问某个页面。以下是一个基于权限的重定向示例:
final goRouter = GoRouter(
routes: [
// ...路由定义...
],
redirect: (state) {
// 检查用户是否具有访问权限
bool hasPermission = checkUserPermission();
if (state.location == '/protected' && !hasPermission) {
return '/login';
}
},
);
在此示例中,我们首先检查用户是否具有访问权限。如果用户尝试访问受保护的页面(/protected
),但没有权限,我们将用户重定向到登录页面(/login
)。其中 checkUserPermission
函数用于检查用户是否具有访问权限,比如如果未登录,则没有访问权限,以下是参考的实现代码:
bool checkUserPermission() {
// 获取登录状态
final SharedPreferences prefs = await SharedPreferences.getInstance();
final isLoggedIn = prefs.getBool('is_logged_in') ?? false;
// 如果未登录,则没有访问权限
if (!isLoggedIn) {
return false;
}
// 获取用户角色
final userRole = prefs.getString('user_role') ?? '';
// 针对具体情况判断用户是否有权访问受保护页面
// 示例:只允许具有 'admin' 角色的用户访问
if (userRole == 'admin') {
return true;
} else {
return false;
}
}
其中,这里可以从应用程序的状态管理器、持久化存储等地方获取用户登录状态及其角色。代码中,我们使用了 SharedPreferences 作为持久化存储,你可以安装模块 shared_preferences
:
flutter pub add shared_preferences
然后在代码中引入:
import 'package:shared_preferences/shared_preferences.dart';
要存储数据到 SharedPreferences,您需要先使用 getInstance() 获取一个 SharedPreferences 实例,然后使用相应的方法存储数据,例如 setBool()、setInt()、setString() 等:
Future<void> saveLoginStatus(bool isLoggedIn) async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool('is_logged_in', isLoggedIn);
}
要从 SharedPreferences 读取数据,仍然需要先获取一个实例,然后使用相应的获取数据的方法,例如 getBool()、getInt()、getString() 等:
Future<bool> getLoginStatus() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final isLoggedIn = prefs.getBool('is_logged_in') ?? false;
return isLoggedIn;
}
默认需要用户是管理员角色,实际中,更多情况是存储在后台的,需要请求后端数据来确认用户权限。在这种情况下,需要在 Flutter 应用中像后端 API 发送请求,然后根据获取的数据判断用户是否具有相应的权限。以下是一个使用 http 库(向后端发起请求)的示例,来获取用户权限并执行 checkUserPermission 函数。你可以安装 dio
模块用于 Http 请求:
flutter pub add dio
然后,在需要发送请求的地方导入 dio 库:
import 'package:dio/dio.dart';
然后从后端获取数据,以实现 checkUserPermission
:
Future<bool> checkUserPermission() async {
// 创建 Dio 实例
Dio dio = Dio();
try {
// 向服务器发起请求获取用户权限数据,以下URL地址仅作示例,请根据您的实际API地址进行修改
final response = await dio.get("https://your-server.com/api/user_permission");
// 提取用户角色
String userRole = response.data["role"];
// 根据请求数据判断用户是否具有管理员权限
if (userRole == "admin") {
return true;
} else {
return false;
}
} catch (e) {
// 如果请求失败,返回false表示没有访问权限
return false;
}
}
6.3.3 实现基于条件的重定向
除了基于权限的重定向外,我们还可以根据其他条件来实现重定向。以下是一个基于条件的重定向示例:
final goRouter = GoRouter(
routes: [
// ...路由定义...
],
redirect: (state) {
// 获取设备类型
final deviceType = getDeviceType();
if (state.location == '/tablet' && deviceType != 'tablet') {
return '/mobile';
}
},
);
在此示例中,我们首先获取设备类型。如果用户尝试访问适用于平板电脑的页面(/tablet
),但设备类型不是平板电脑,我们将用户重定向到适用于手机的页面(/mobile
)。
6.3.4 小结
本节介绍了如何在使用go_router
模块的 Flutter 应用中实现重定向。我们首先定义了一个重定向函数,然后介绍了如何实现基于权限和条件的重定向。
通过使用go_router
实现重定向,您可以更好地管理应用的页面跳转逻辑,从而提高用户体验和应用安全性。在接下来的章节中,我们将继续介绍 go_router
模块的其他功能,如动画导航等。
7. 路由守卫与路由过渡动画
7.1 路由守卫的作用与实现
在本节中,我们将介绍路由守卫的概念以及如何在使用go_router
模块的 Flutter 应用中实现路由守卫。路由守卫是一种在用户尝试访问某个页面之前执行的拦截器,可以用于权限控制、数据预加载等场景。
7.1.1 路由守卫的作用
路由守卫的主要作用如下:
- 权限控制:在用户访问受保护的页面之前,检查用户是否具有访问权限。如果没有权限,可以重定向到登录页面或显示提示信息。
- 数据预加载:在用户访问某个页面之前,预先加载所需的数据。这可以提高页面加载速度,提升用户体验。
- 页面跳转控制:在用户访问某个页面之前,根据特定条件决定是否允许页面跳转。
7.1.2 实现路由守卫
要在go_router
模块中实现路由守卫,我们需要为每个需要守卫的路由定义一个guard
函数。以下是一个简单的路由守卫示例:
// 路由守卫函数
Future<bool> authGuard(BuildContext context, GoRouterState state) async {
// 检查用户是否具有访问权限
bool hasPermission = await checkUserPermission();
if (!hasPermission) {
// 如果没有权限,重定向到登录页面
GoRouter.of(context).go('/login');
return false;
}
return true;
}
final goRouter = GoRouter(
routes: [
GoRoute(
path: '/protected',
pageBuilder: (context, state) {
return MaterialPage(child: ProtectedPage());
},
guards: [authGuard],
),
// ...其他路由定义...
],
);
在此示例中,我们首先定义了一个名为authGuard
的路由守卫函数。该函数检查用户是否具有访问权限,如果没有权限,则重定向到登录页面,并返回false
以阻止页面跳转。
然后,我们在GoRoute
中为受保护的页面(/protected
)添加了guards
属性,并将authGuard
函数作为守卫。
7.1.3 小结
本节介绍了路由守卫的作用以及如何在使用go_router
模块的 Flutter 应用中实现路由守卫。路由守卫是一种在用户尝试访问某个页面之前执行的拦截器,可以用于权限控制、数据预加载等场景。通过使用go_router
实现路由守卫,您可以更好地管理应用的页面跳转逻辑,从而提高用户体验和应用安全性。
7.2 使用 go_router 实现路由守卫
在本节中,我们将深入讨论如何使用go_router
模块实现路由守卫。我们将从一个简单的权限控制场景开始,然后讨论如何实现更复杂的路由守卫功能。
7.2.1 示例:权限控制
假设我们的应用有两个页面:一个登录页面和一个受保护的页面。用户只有在登录后才能访问受保护的页面。我们可以使用go_router
的路由守卫功能来实现这个需求。
首先,我们需要为受保护的页面定义一个路由守卫函数,如下所示:
Future<bool> authGuard(BuildContext context, GoRouterState state) async {
// 检查用户是否已登录
bool isLoggedIn = await checkUserLoggedIn();
if (!isLoggedIn) {
// 如果用户未登录,重定向到登录页面
GoRouter.of(context).go('/login');
return false;
}
return true;
}
然后,在GoRoute
中为受保护的页面添加guards
属性,并将authGuard
函数作为守卫:
final goRouter = GoRouter(
routes: [
GoRoute(
path: '/protected',
pageBuilder: (context, state) {
return MaterialPage(child: ProtectedPage());
},
guards: [authGuard],
),
// ...其他路由定义...
],
);
现在,只有在用户登录后才能访问受保护的页面。如果用户未登录,他们将被重定向到登录页面。
7.2.2 示例:数据预加载
在某些情况下,我们可能希望在用户访问页面之前预先加载一些数据。我们可以使用路由守卫来实现这个功能。
首先,我们需要定义一个路由守卫函数,用于加载数据:
Future<bool> loadDataGuard(BuildContext context, GoRouterState state) async {
// 加载所需的数据
await loadData();
return true;
}
然后,在GoRoute
中为需要预加载数据的页面添加guards
属性,并将loadDataGuard
函数作为守卫:
final goRouter = GoRouter(
routes: [
GoRoute(
path: '/data',
pageBuilder: (context, state) {
return MaterialPage(child: DataPage());
},
guards: [loadDataGuard],
),
// ...其他路由定义...
],
);
现在,在用户访问数据页面之前,loadDataGuard
函数将被调用以加载数据。
7.2.3 小结
本节深入讨论了如何使用go_router
模块实现路由守卫。我们通过两个示例展示了如何实现权限控制和数据预加载功能。通过使用go_router
实现路由守卫,您可以更好地管理应用的页面跳转逻辑,从而提高用户体验和应用安全性。
8. go_router 过渡动画
在章中,我们将讨论如何使用 go_router
模块为 Flutter 应用程序的页面切换添加自定义过渡动画。默认情况下,Flutter 提供了一些基本的页面过渡效果,但有时我们可能需要自定义这些效果以提高用户体验。通过使用go_router
模块,我们可以轻松地实现自定义过渡动画。
8.1 示例:淡入淡出动画
我们将首先创建一个简单的淡入淡出过渡动画。为此,我们需要在GoRoute
的pageBuilder
属性中使用CustomTransitionPage
组件。以下示例演示了如何为页面切换添加淡入淡出动画:
final goRouter = GoRouter(
routes: [
GoRoute(
path: '/fade',
pageBuilder: (context, state) {
return CustomTransitionPage(
transitionsBuilder: (context, animation, secondaryAnimation, child) {
return FadeTransition(
opacity: animation,
child: child,
);
},
child: FadePage(),
);
},
),
// ...其他路由定义...
],
);
在这个例子中,我们使用了CustomTransitionPage
组件,并将transitionsBuilder
属性设置为一个返回FadeTransition
的函数。这将使页面切换时产生淡入淡出效果。
8.2 示例:缩放动画
接下来,我们将创建一个缩放过渡动画。与上一个示例类似,我们将使用CustomTransitionPage
组件,并将transitionsBuilder
属性设置为一个返回ScaleTransition
的函数。以下示例演示了如何为页面切换添加缩放动画:
final goRouter = GoRouter(
routes: [
GoRoute(
path: '/scale',
pageBuilder: (context, state) {
return CustomTransitionPage(
transitionsBuilder: (context, animation, secondaryAnimation, child) {
return ScaleTransition(
scale: animation,
child: child,
);
},
child: ScalePage(),
);
},
),
// ...其他路由定义...
],
);
在这个例子中,我们使用了CustomTransitionPage
组件,并将transitionsBuilder
属性设置为一个返回ScaleTransition
的函数。这将使页面切换时产生缩放效果。
8.3 示例:组合动画
我们还可以组合多个过渡动画以创建更复杂的效果。以下示例演示了如何将淡入淡出动画和缩放动画组合在一起:
final goRouter = GoRouter(
routes: [
GoRoute(
path: '/combined',
pageBuilder: (context, state) {
return CustomTransitionPage(
transitionsBuilder: (context, animation, secondaryAnimation, child) {
return FadeTransition(
opacity: animation,
child: ScaleTransition(
scale: animation,
child: child,
),
);
},
child: CombinedPage(),
);
},
),
// ...其他路由定义...
],
);
在这个例子中,我们将FadeTransition
和ScaleTransition
组件嵌套在一起,以同时应用淡入淡出和缩放效果。
8.4 小结
本章介绍了如何使用go_router
模块为 Flutter 应用程序的页面切换添加自定义过渡动画。我们通过三个示例展示了如何实现淡入淡出动画、缩放动画以及组合动画。通过使用go_router
模块实现自定义路由过渡动画,可以改善用户体验并为应用添加更好的视觉效果。
F. 附录
F.1 Flutter Route 类 API
F.1.1 Route<T> 类构造器
Route({RouteSettings? settings})
用于初始化 Route。其中 RouteSettings 类为可能对构建 Route 有用的数据。
RouteSettings 具有以下属性:
属性 | 类型 | 标签 | 描述 |
---|---|---|---|
arguments | Object? | final | 传递到此 Route 的参数。 |
hashCode | int | read-only、inherited | 此对象的哈希代码。 |
name | String? | final | Route的名称(例如,“/settings”)。 |
runtimeType | Type | read-only、inherited | 对象运行时类型的表示形式。 |
F.1.2 Route<T> 类属性
属性 | 类型 | 标签 | 描述 |
---|---|---|---|
currentResult | T? | read-only | 当弹出此路径时(参见Navigator.pop ),如果未指定结果或结果为空,将使用此值。 |
hasActiveRouteBelow | bool | read-only | 此路由下是否至少有一个活动路由。 |
hashCode | int | read-only、inherited | 此对象的哈希码。 |
isActive | bool | read-only | 这条路线是否在导航器上。 |
isCurrent | bool | read-only | 此路由是否是导航器上的最顶层(当前)路由。 |
isFirst | bool | read-only | 此路由是否是导航器上最底部的活动路由。 |
navigator | NavigatorState? | read-only | 路由所在的导航器(如果有)。 |
overlayEntries | List<OverlayEntry> | read-only | 此路由的覆盖条目。 |
popped | Future<T?> | read-only | 当这条路由从导航器中弹出时,Future就完成了 |
restorationScopeId | ValueListenable<String?> | read-only | 用于此路由周围的 RestorationScope 的还原范围ID。 |
runtimeType | Type | read-only、inherited | 对象运行时类型的表示形式。 |
settings | RouteSettings | read-only | 此路由的设置。 |
willHandlePopInternally | bool | read-only | 调用 didPop 是否会返回false。 |
F.1.3 Route<T> 类方法
changedExternalState() → void
每当 导航器(Navigator)以某种可能影响路线的方式更新时调用,以指示路线可能也希望重建。
changedInternalState() → void
每当路由的内部状态改变时调用。
didAdd() → void
将路线添加到导航器后,在 安装 后调用。
didChangeNext(Route? nextRoute) → void
此路由的下一条路线已更改为给定的新路由。
didChangePrevious(Route? previousRoute) → void
此路由的先前路由已更改为给定的新路由。
didComplete(T? result) → void
该路由被弹出或者正被优雅地移除。
didPop(T? result) → bool
弹出此路由的请求。
- 如果路由可以在内部处理它(例如,因为它有自己的内部状态堆栈),则返回false;
- 否则返回true(通过返回调用super.didPop的值)。返回false将阻止NavigatorState.pop的默认行为。
didPopNext(Route nextRoute) → void
位于这条路由上方的给定路由已从导航器中弹(pop)出。
didPush() → TickerFuture
当路由被 push 到导航器上时,在安装后调用。
didReplace(Route? oldRoute) → void
当导航器中的路线替换了另一个路由时,在安装后调用。
dispose() → void
丢弃对象使用的任何资源。
install() → void
当路由插入导航器时调用。
willPop() → Future
返回当此 Route 是当前路由 (is current) 时调用 Navigator.maybePop
是否应该执行任何操作。
F.2 Flutter Navigator 类 API
导航器会将其 Navigator.pages
转换为一个路由堆栈(如果提供的话)。Navigator.pages
中的更改将触发路由堆栈的更新。导航器将更新其路由以匹配其Navigator.pages的新配置。要使用此 API,可以创建一个 Page 子类并为 ·Navigator.pages· 定义一个页面列表。还需要 Navigator.onPopPage
回调以在弹出时正确清理输入页面。
默认情况下,导航器将使用 DefaultTransitionDelegate 来决定路线如何进出屏幕。要自定义它,请定义一个 TransitionDelegate 子类,并将其提供给 Navigator.transitionDelegate
。
有关使用pages API的更多信息,请参见 Router 部件。
F.2.1 Navigator 类属性
属性 | 类型 | 标签 | 描述 |
---|---|---|---|
clipBehavior | Clip | final | 根据此选项,内容将被剪切(或不被剪切)。 |
hashCode | int | read-only, inherited | 此对象的哈希码。 |
initialRoute | String? | final | 显示的第一个路由的名称。 |
key | Key? | final, inherited | 控制树中一个 Widget 如何替换另一个 Widget。 |
observers | List | final | 此 Navigator 的观察者列表。 |
onGenerateInitialRoutes | RouteListFactory | final | 当 Widget 创建时,如果 initialRoute 不为 null,则调用此函数以生成初始的 Route 对象列表。 |
onGenerateRoute | RouteFactory? | final | 为给定的 RouteSettings 生成路由时调用。 |
onPopPage | PopPageCallback? | final | 当调用 pop 时,但当前路由对应于 pages 列表中的 Page 时调用。 |
onUnknownRoute | RouteFactory? | final | 当 onGenerateRoute 无法生成路由时调用。 |
pages | List<Page> | final | 用于填充历史记录的页面列表。 |
reportsRouteUpdateToEngine | bool | final | 当最顶层路由发生变化时,此 Navigator 是否应向引擎报告路由更新消息。 |
requestFocus | bool | final | 当将新路由推送到 Navigator 时,Navigator 及其最顶层路由是否应请求焦点。 |
restorationScopeId | String? | final | 恢复 Navigator 的状态的 ID,包括其历史记录。 |
routeTraversalEdgeBehavior | TraversalEdgeBehavior | final | 控制在路由内部的 Widget 之间定义焦点遍历的焦点范围的第一个和最后一个项目之外的焦点传递。 |
runtimeType | Type | read-only, inherited | 对象的运行时类型表示。 |
transitionDelegate | TransitionDelegate | final | 用于决定在页面更新期间路由如何进入或离开屏幕的委托。 |
F.2.2 Navigator 类方法
方法 | 返回类型 | 标签 | 描述 |
---|---|---|---|
createElement() | StatefulElement | inherited | 创建一个 StatefulElement 来管理这个小部件在树中的位置。 |
createState() | NavigatorState | override | 在树中的给定位置创建该小部件的可变状态。 |
debugDescribeChildren() | List<DiagnosticsNode> | inherited | 返回描述此节点子节点的 DiagnosticsNode 对象列表。 |
debugFillProperties() | void | inherited | 添加与节点关联的其他属性。 |
noSuchMethod() | dynamic | inherited | 当访问不存在的方法或属性时调用。 |
toDiagnosticsNode() | DiagnosticsNode | inherited | 返回用于调试工具和 DiagnosticsNode.toStringDeep 的对象的调试表示。 |
toString() | String | inherited | 该对象的字符串表示。 |
toStringDeep() | String | inherited | 返回此节点及其子节点的字符串表示形式。 |
toStringShallow() | String | inherited | 返回该对象的一行详细描述。 |
toStringShort() | String | inherited | 该小部件的简短文本描述。 |
F.2.2 Navigator 类静态方法
方法 | 返回类型 | 描述 |
---|---|---|
canPop (BuildContext context) | bool | 检查最紧密包围给定上下文的导航器是否可以弹出。 |
defaultGenerateInitialRoutes (NavigatorState navigator, String initialRouteName) | List<Route> | 将路由名称转换为一组 Route 对象。 |
maybeOf (BuildContext context, {bool rootNavigator = false}) | NavigatorState? | 返回包围给定上下文的最近一次实例的状态,如果有的话。 |
maybePop <T extends Object?>(BuildContext context, [T? result]) | Future<bool> | 调用当前路由的 Route.willPop 方法,并根据结果采取相应的操作,可能作为结果弹出路由;返回是否应该将弹出请求视为已处理。 |
of (BuildContext context, {bool rootNavigator = false}) | NavigatorState | 返回包围给定上下文的最近一次实例的状态。 |
pop <T extends Object?>(BuildContext context, [T? result]) | void | 从最紧密包围给定上下文的导航器中弹出最顶层的路由。 |
popAndPushNamed <T extends Object?, TO extends Object?>(BuildContext context, String routeName, {TO? result, Object? arguments}) | Future<T?> | 弹出最紧密包围给定上下文的当前路由,并在其位置推入一个具名路由。 |
popUntil (BuildContext context, RoutePredicate predicate) | void | 在最紧密包围给定上下文的导航器上重复调用 pop,直到断言函数返回 true。 |
push <T extends Object?>(BuildContext context, Route<T> route) | Future<T?> | 将给定的路由推入最紧密包围给定上下文的导航器中。 |
pushAndRemoveUntil <T extends Object?>(BuildContext context, Route<T> newRoute, RoutePredicate predicate) | Future<T?> | 将给定的路由推入最紧密包围给定上下文的导航器中,然后移除所有之前的路由,直到断言函数返回 true。 |
pushNamed <T extends Object?>(BuildContext context, String routeName, {Object? arguments}) | Future<T?> | 将一个具名路由推入最紧密包围给定上下文的导航器中。 |
pushNamedAndRemoveUntil <T extends Object?>(BuildContext context, String newRouteName, RoutePredicate predicate, {Object? arguments}) | Future<T?> | 将具有给定名称的路由推入最紧密包围给定上下文的导航器中,并移除之前的所有路由,直到断言函数返回 true。 |
pushReplacement <T extends Object?, TO extends Object?>(BuildContext context, Route<T> newRoute, {TO? result}) | Future<T?> | 通过推入给定的路由并在新路由动画完成后销毁前一个路由,替换最紧密包围给定上下文的导航器的当前路由。 |
pushReplacementNamed <T extends Object?, TO extends Object?>(BuildContext context, String routeName, {TO? result, Object? arguments}) | Future<T?> | 通过推入具名路由并在新路由动画完成后销毁前一个路由,替换最紧密包围给定上下文的导航器的当前路由。 |
removeRoute (BuildContext context, Route route) | void | 立即从最紧密包围给定上下文的导航器中移除路由,并调用 Route.dispose 方法进行处理。 |
removeRouteBelow (BuildContext context, Route anchorRoute) | void | 立即从最紧密包围给定上下文的导航器中移除位于给定 anchorRoute 下方的路由,并调用 Route.dispose 方法进行处理。 |
replace <T extends Object?>(BuildContext context, {required Route oldRoute, required Route<T> newRoute}) | void | 使用新路由替换最紧密包围给定上下文的导航器上的现有路由。 |
replaceRouteBelow <T extends Object?>(BuildContext context, {required Route anchorRoute, required Route<T> newRoute}) | void | 使用新路由替换最紧密包围给定上下文的导航器上给定 anchorRoute 下方的现有路由。 |
restorablePopAndPushNamed <T extends Object?, TO extends Object?> | String | 将最紧密包围给定上下文的导航器中的当前路由弹出并推入一个具名路由。 |
restorablePush <T extends Object?> | String | 在最紧密包围给定上下文的导航器中推入一个新路由。 |
restorablePushAndRemoveUntil <T extends Object?> | String | 在最紧密包围给定上下文的导航器中推入一个新路由,并删除之前的所有路由,直到断言函数返回 true。 |
restorablePushNamed <T extends Object?> | String | 在最紧密包围给定上下文的导航器中推入一个具名路由。 |
restorablePushNamedAndRemoveUntil <T extends Object?> | String | 将具有给定名称的路由推入最紧密包围给定上下文的导航器中,并删除之前的所有路由,直到断言函数返回 true。 |
restorablePushReplacement <T extends Object?, TO extends Object?> | String | 通过推入一个新路由并在新路由动画完成后销毁前一个路由,替换最紧密包围给定上下文的导航器的当前路由。 |
restorablePushReplacementNamed <T extends Object?, TO extends Object?> | String | 通过推入具名路由并在新路由动画完成后销毁前一个路由,替换最紧密包围给定上下文的导航器的当前路由。 |
restorableReplace <T extends Object?> | String | 使用新路由替换最紧密包围给定上下文的导航器上的现有路由。 |
restorableReplaceRouteBelow <T extends Object?> | String | 使用新路由替换最紧密包围给定上下文的导航器上给定 anchorRoute 下方的现有路由。 |
F.3 go_router 模块的 GoRouter 类
【注意】:GoRouter 和 GoRoute 是两个类。
- GoRouter 类是 go_router 的核心类,负责管理整个应用程序的路由系统。它维护了一个路由配置(RouteConfiguration),管理路由信息的解析(GoRouteInformationParser)和提供(GoRouteInformationProvider),以及控制页面导航和路由状态的变化。GoRouter 类提供了一系列方法来处理路由的导航、添加监听器、刷新路由等操作,如 push、pop、replace、addListener、refresh 等。
- GoRoute 类是表示单个路由的对象。它定义了一个具体的路由路径、参数和相关的操作。每当用户导航到一个新的路由时,GoRouter 会创建一个对应的 GoRoute 对象,并将其添加到路由堆栈中。GoRoute 类提供了一些方法来处理路由的生成、匹配、跳转和导航等操作,如 go、goNamed、namedLocation、replaceNamed 等。 总结来说,GoRouter 类是整个路由系统的管理者,负责路由的整体控制和状态管理,而 GoRoute 类是单个路由的表示和操作者,负责具体路由的生成、匹配和导航等操作。 例如:
import 'package:go_router/go_router.dart'; // 定义路由配置 final routeConfig = RouteConfiguration( routes: { '/': (context) => HomePage(), // 根路由 '/settings': (context) => SettingsPage(), // 设置页面路由 '/profile/:username': (context, state) => ProfilePage(username: state.params['username']), // 用户个人资料页面路由 }, ); // 创建 GoRouter 实例 final goRouter = GoRouter( routes: routeConfig.routes, errorPageBuilder: (context, state) => ErrorPage(), // 错误页面 ); // 在 MaterialApp 或 CupertinoApp 中使用 goRouter.routerDelegate 作为路由委托 MaterialApp( ... routerDelegate: goRouter.routerDelegate, backButtonDispatcher: goRouter.backButtonDispatcher, ... ); // 在任何需要进行路由导航的地方,可以通过 goRouter 实例进行操作 void navigateToSettings() { goRouter.pushNamed('/settings'); } void navigateToProfile(String username) { goRouter.goNamed('/profile/:username', pathParameters: {'username': username}); }
go_router 模块中提供了一个 GoRouter 对象,用于定义和管理应用程序的路由。
GoRouter 是 go_router 库的核心类,它负责路由的注册、导航和页面渲染。通过创建一个 GoRouter 对象,你可以配置应用程序的路由规则并管理不同页面之间的导航。
在创建 GoRouter 对象时,你可以指定一组路由规则。每个路由规则由一个路径模式和一个处理程序(Handler)组成。路径模式是一个字符串,用于匹配特定的 URL 路径。处理程序则定义了当路径与模式匹配时要执行的操作,通常是展示相应的页面。
GoRouter 对象提供了多个方法来管理路由和导航,包括:
push
:将指定的路径推入导航堆栈,导航到相应的页面。pop
:将当前页面从导航堆栈中弹出,返回上一个页面。replace
:替换当前页面为指定的路径对应的页面。navigateTo
:根据给定的路径导航到相应的页面。
除了基本的导航功能外,GoRouter 还支持以下特性:
- 参数传递:你可以在导航时传递参数,以便在目标页面上使用。
- 嵌套路由:你可以在页面中嵌套多个 GoRouter 对象,实现更复杂的路由结构。
- 路由守卫:你可以定义路由守卫,用于在导航到页面之前执行一些操作,如验证用户权限等。
以下是 GoRouter 对象的属性和方法的解析:
GoRouter 对象的属性
属性 | 类型 | 标签 | 描述 |
---|---|---|---|
backButtonDispatcher | BackButtonDispatcher | final | 用于配置 Router 的 BackButtonDispatcher。 |
configuration | RouteConfiguration | late final | GoRouter 使用的路由配置。 |
hashCode | int | read-only inherited | 此对象的哈希码。 |
hasListeners | bool | read-only inherited | 当前是否有任何监听器已注册。 |
location | String | read-only | 获取当前位置。 |
routeInformationParser | GoRouteInformationParser | late final override-getter | GoRouter 使用的路由信息解析器。 |
routeInformationProvider | GoRouteInformationProvider | late final override-getter | GoRouter 使用的路由信息提供器。 |
routerDelegate | GoRouterDelegate | late final override-getter | 路由代理。在 MaterialApp 或 CupertinoApp 的 .router() 构造函数中提供此对象。 |
runtimeType | Type | read-only inherited | 对象的运行时类型表示。 |
GoRouter 对象的方法
方法 | 返回类型 | 标签 | 描述 |
---|---|---|---|
addListener (VoidCallback listener) | void | inherited | 注册一个闭包,在对象发生变化时调用。 |
canPop () | bool | 如果可以弹出至少两个或更多路由,则返回 true。 | |
dispose () | void | 释放对象使用的任何资源。调用此方法后,对象将处于不可用状态,应将其丢弃(在对象被处理后,调用 addListener 将引发异常)。 | |
go (String location, {Object? extra}) | void | 导航到指定的 URI 位置,可选包含查询参数,例如 /family/f2/person/p1?color=blue。 | |
goNamed (String name, {Map<String, String> pathParameters = const <String, String>{}, Map<String, dynamic> queryParameters = const <String, dynamic>{}, Object? extra}) | void | 导航到指定的命名路由,可选包含参数,例如 name='person',pathParameters={'fid': 'f2', 'pid': 'p1'}。 | |
namedLocation (String name, {Map<String, String> pathParameters = const <String, String>{}, Map<String, dynamic> queryParameters = const <String, dynamic>{}}) | String | 根据路由名称和参数获取位置。这对于重定向到命名位置非常有用。 | |
noSuchMethod (Invocation invocation) | dynamic | inherited | 当访问不存在的方法或属性时调用。 |
notifyListeners () | void | inherited | 调用所有注册的监听器。 |
pop <T extends Object?>([T? result]) | void | 弹出当前屏幕上最顶部的路由。 | |
push <T extends Object?>(String location, {Object? extra}) | Future<T?> | 将 URI 位置推入页面堆栈中,可选包含查询参数,例如 /family/f2/person/p1?color=blue。 | |
pushNamed <T extends Object?>(String name, {Map<String, String> pathParameters = const <String, String>{}, Map<String, dynamic> queryParameters = const <String, dynamic>{}, Object? extra}) | Future<T?> | 将命名路由推入页面堆栈中,可选包含参数,例如 name='person',pathParameters={'fid': 'f2', 'pid': 'p1'}。 | |
pushReplacement <T extends Object?>(String location, {Object? extra}) | Future<T?> | 使用给定的 URL 位置替换页面堆栈中的最顶部页面,可选包含查询参数,例如 /family/f2/person/p1?color=blue。 | |
pushReplacementNamed <T extends Object?>(String name, {Map<String, String> pathParameters = const <String, String>{}, Map<String, dynamic> queryParameters = const <String, dynamic>{}, Object? extra}) | Future<T?> | 使用命名路由替换页面堆栈中的最顶部页面,可选包含参数,例如 name='person',pathParameters={'fid': 'f2', 'pid': 'p1'}。 | |
refresh () | void | 刷新路由。 | |
removeListener (VoidCallback listener) | void | inherited | 从注册的闭包列表中移除先前注册的闭包,这些闭包在对象发生变化时被通知。 |
replace (String location, {Object? extra}) | Future<T?> | 将页面堆栈中的最顶部页面替换为给定页面,但将其视为同一页面。 | |
replaceNamed (String name, {Map<String, String> pathParameters = const <String, String>{}, Map<String, dynamic> queryParameters = const <String, dynamic>{}, Object? extra}) | Future<T?> | 使用命名路由替换最顶部的页面,并保留页面键和可选参数。 | |
restore (RouteMatchList matchList) | void | 恢复 RouteMatchList。 | |
toString () | String | inherited | 返回对象的字符串表示形式。 |
GoRouter 对象的静态属性和静态方法
属性 | 类型 | 标签 | 描述 |
---|---|---|---|
optionURLReflectsImperativeAPIs | bool | read / write | 命令式API是否影响浏览器地址栏。 |
方法 | 返回类型 | 描述 |
---|---|---|
maybeOf (BuildContext context) | GoRouter | 小部件树中的当前GoRouter(如果有)。 |
of (BuildContext context) | GoRouter | 在小部件树中查找当前的GoRouter。 |
转载自:https://juejin.cn/post/7283799929402425401