Flutter开发笔记:Flutter路由技术

简介: Flutter开发笔记:Flutter路由技术

FlutterFlutter开发笔记:路由技术


1. 概述

1.1 移动端路由简介

移动端应用开发中,路由技术是一个非常重要的组成部分。路由技术负责管理应用中各个页面之间的跳转、导航以及参数传递等关键功能。在移动端应用中,一个高效、易于维护的路由系统对于提高开发效率和用户体验具有重要意义。

1.2 本文内容导航

本文将对 Flutter 移动端应用开发中的路由技术进行详细讲解,内容涵盖以下几个方面:

  • Flutter 路由基础知识,包括核心概念、基本操作以及传参等;
  • 命名路由与动态路由的定义、使用以及对比;
  • go_router 模块的介绍,包括安装、配置、定义和注册路由等;
  • 使用 go_router 实现页面导航、处理深度链接、重定向等高级功能;
  • 路由守卫与路由过渡动画的实现;
  • 通过实战案例,展示如何使用 go_router 构建一个完整的移动端应用。

通过学习本文,可以掌握 Flutter 路由技术的基本原理和实践方法,为开发高质量的移动端应用奠定坚实基础。

2. Flutter 路由基础

2.1 路由的核心:Route 和 Navigator

Flutter 中,路由技术的核心概念包括两个要素:RouteNavigator

2.1.1 Route

Route 代表应用中的一个页面,它包含了页面的布局、逻辑以及生命周期等信息。在 Flutter 中,Route通常是一个继承自PageRoute的类。

PageRoute是一个抽象类,表示一个可以用于Navigator的页面。它包含了页面的构建方法、过渡动画以及页面的生命周期回调等属性。在实际开发中,我们通常会使用以下两种PageRoute:MaterialPageRouteCupertinoPageRoute

  • MaterialPageRoute:一个实现了Material Design风格的页面路由,它提供了平台特定的页面切换动画。在Android设备上,页面从底部滑入;在iOS设备上,页面从右侧滑入。如:
// 使用MaterialPageRoute创建一个新页面
MaterialPageRoute(builder: (context) => NewPage());
  • CupertinoPageRoute:一个实现了Cupertino风格(iOS风格)的页面路由,它提供了iOS平台特定的页面切换动画。如:
// 使用CupertinoPageRoute创建一个新页面
CupertinoPageRoute(builder: (context) => NewPage());

2.1.2 Navigator(导航器)

Flutter 中,路由技术的另外一个核心概念是 NavigatorNavigator 是一个管理应用页面栈的组件,它负责处理页面之间的跳转、导航以及参数传递等操作。在 Flutter 中,Navigator类是一个关键的组件,它提供了一系列方法来实现页面间的导航

Navigator 是一个管理应用页面栈的组件,它负责处理页面之间的跳转、导航以及参数传递等操作。它通过一个栈结构来管理应用中的页面。当一个新页面被打开时,它会被压入栈顶;当一个页面被关闭时,它会从栈顶弹出。通过对栈的操作,Navigator实现了页面间的跳转和导航。

Navigator 类是一个关键的组件,它提供了一系列方法来实现页面间的导航。包括:

方法 描述
push 将一个新的页面压入栈顶,实现从当前页面跳转到新页面的功能。
pop 将栈顶的页面弹出,实现从当前页面返回到上一个页面的功能。
replace 将栈中的某个页面替换为新的页面。
pushAndRemoveUntil 将一个新的页面压入栈顶,并移除栈中指定条件的页面。
pushNamed 通过页面的名称进行跳转。
popAndPushNamed 弹出当前页面并跳转到指定名称的页面。

为了在应用中使用Navigator,我们需要将其添加到应用的组件树中。在实际开发中,我们通常会在MaterialAppCupertinoApp 组件中配置 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方法将一个新的页面压入栈顶,从而实现页面跳转的功能。

页面跳转的主要步骤如下:

  1. 定义新页面的Route对象,如MaterialPageRouteCupertinoPageRoute
  2. 使用Navigator.push方法跳转到新页面。

例如:

// 定义新页面的Route对象
MaterialPageRoute newPageRoute = MaterialPageRoute(builder: (context) => NewPage());
// 使用Navigator.push方法跳转到新页面
Navigator.of(context).push(newPageRoute);

通过Navigator.push方法,我们可以实现从当前页面跳转到新页面的功能。在实际开发中,我们通常会使用MaterialPageRouteCupertinoPageRoute来创建新页面的Route对象。

2.2.2 页面返回

页面返回是指从当前页面返回到上一个页面的过程。在 Flutter 中,我们可以使用 Navigator.pop 方法将栈顶的页面弹出,从而实现页面返回的功能。

页面返回的主要步骤如下:

  1. 使用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 中,我们可以在MaterialAppCupertinoApproutes属性中定义命名路由。

以下是一个具体的代码示例:

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 中,我们可以通过MaterialAppCupertinoApponGenerateRoute属性来定义动态路由。

以下是一个具体的代码示例:

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 命名路由与动态路由的对比

下面是命名路由和动态路由的对比:

  1. 定义方式:命名路由通过MaterialAppCupertinoApproutes属性定义,而动态路由通过onGenerateRoute属性定义。
  2. 参数传递:命名路由在进行页面跳转时,需要将参数定义在路由名称中,而动态路由可以通过arguments属性直接传递参数。
  3. 灵活性:动态路由相比于命名路由更加灵活,因为它可以根据传入的参数动态生成路由,而命名路由需要预先定义好所有的路由名称。
  4. 易用性:对于简单的页面跳转,命名路由更加易用,因为它只需要预先定义好路由名称即可。然而,在需要根据参数动态生成路由的场景下,动态路由更加方便。

3.3.2 适用场景

下面是命名路由和动态路由各自适用的场景:

  1. 命名路由:适用于简单的页面跳转,无需根据参数动态生成路由的场景。例如,从主页跳转到关于页面,或从商品列表页跳转到商品详情页等。
  2. 动态路由:适用于需要根据参数动态生成路由的场景。例如,从用户列表页跳转到用户详情页时,需要根据用户ID生成不同的用户详情页面;或者在一个新闻应用中,根据不同的新闻类别生成不同的新闻列表页面等。

3.3.3 小结

本节通过对比命名路由和动态路由的特点,以及它们各自适用的场景,帮助您更好地理解这两种路由方式的差异。在实际项目中,您可以根据具体需求选择合适的路由方式。总的来说,对于简单的页面跳转,命名路由更加易用;而在需要根据参数动态生成路由的场景下,动态路由更加方便。

在接下来的章节中,我们将继续深入讲解 Flutter 路由的其他知识点,以帮助您更好地掌握 Flutter 路由的使用方法。

4. go_router 模块介绍

4.1 go_router 模块的特点

在本节中,我们将介绍 go_router 模块的优势与特点。go_router是一个用于 Flutter 的路由库,它提供了一种简洁、强大且易于维护的路由管理方式。

go_router模块有以下优势:

  1. 类型安全go_router模块支持类型安全的路由参数传递,可以有效地减少因参数类型错误而导致的运行时错误。
  2. 代码简洁go_router模块采用声明式的编程方式,可以让您的代码更加简洁、易读和易于维护。
  3. 功能丰富go_router模块提供了多种路由功能,包括命名路由、动态路由、路由守卫、路由重定向等,可以满足各种复杂场景的需求。
  4. 与现有框架兼容go_router模块与其他 Flutter 框架(如Provider、Riverpod、GetX等)兼容良好,可以方便地集成到您的项目中。

从功能上上看, go_router 模块有以下特点:

  1. 命名路由go_router模块支持命名路由,可以让您更方便地管理和跳转到指定页面。
  2. 动态路由go_router模块支持动态路由,可以根据传入的参数生成不同的路由,适用于需要根据参数动态生成路由的场景。
  3. 路由守卫go_router模块支持路由守卫,可以在路由跳转过程中添加条件判断,例如进行身份验证、权限检查等。
  4. 路由重定向go_router模块支持路由重定向,可以根据需要将用户从一个路由重定向到另一个路由。
  5. 浏览器支持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.routerCupertinoApp.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对象。您可以在此处创建并返回您的页面(如MaterialPageCupertinoPage等)。

以下是一个定义路由的示例:

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对象的gogoNamed方法,您可以在您的 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类的gogoNamedgoBackgoTo方法,您可以在您的 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 使用类型安全的方式传递参数

为了避免在传递参数时出现类型错误,您可以使用GoRouteparamsBuilder属性定义一个类型安全的参数构建器。以下是一个定义类型安全参数构建器的示例:

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参数,您可以轻松地在页面间传递参数。同时,您还可以使用GoRouteparamsBuilder属性定义类型安全的参数构建器,以避免在传递参数时出现类型错误。在接下来的章节中,我们将继续深入讲解go_router模块的使用方法,包括如何使用路由守卫、处理页面过渡动画等。

6. 处理深度链接与重定向

6.1 深度链接的概念与应用

深度链接(Deep Linking)是一种允许用户直接打开应用内特定页面的技术。通过深度链接,您可以将用户从网页、广告、电子邮件或其他应用直接导航到您的应用的特定页面,而不仅仅是应用的主页面。这有助于提高用户体验,增加用户参与度,并提高应用的转化率。

在本节中,我们将介绍深度链接的概念,以及如何在使用go_router模块的 Flutter 应用中处理深度链接。

6.1.1 深度链接的类型

深度链接主要分为两种类型:

  1. 普通深度链接(Standard Deep Links):这种类型的深度链接使用标准的URL格式,例如https://example.com/details/123。当用户点击此类链接时,应用会尝试打开对应的页面。如果应用尚未安装,用户将被重定向到应用商店。
  2. 通用链接(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_routerFlutter 应用中处理深度链接,您需要将深度链接的 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 路由守卫的作用

路由守卫的主要作用如下:

  1. 权限控制:在用户访问受保护的页面之前,检查用户是否具有访问权限。如果没有权限,可以重定向到登录页面或显示提示信息。
  2. 数据预加载:在用户访问某个页面之前,预先加载所需的数据。这可以提高页面加载速度,提升用户体验。
  3. 页面跳转控制:在用户访问某个页面之前,根据特定条件决定是否允许页面跳转。

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 示例:淡入淡出动画

我们将首先创建一个简单的淡入淡出过渡动画。为此,我们需要在GoRoutepageBuilder属性中使用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(),
        );
      },
    ),
    // ...其他路由定义...
  ],
);

在这个例子中,我们将FadeTransitionScaleTransition组件嵌套在一起,以同时应用淡入淡出和缩放效果。

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 是两个类。

  1. GoRouter 类是 go_router 的核心类,负责管理整个应用程序的路由系统。它维护了一个路由配置(RouteConfiguration),管理路由信息的解析(GoRouteInformationParser)和提供(GoRouteInformationProvider),以及控制页面导航和路由状态的变化。GoRouter 类提供了一系列方法来处理路由的导航、添加监听器、刷新路由等操作,如 push、pop、replace、addListener、refresh 等。
  2. 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 对象的属性和方法的解析:

在 pub.dev 文档中,GoRoute 类的文档地址为: https://pub.dev/documentation/go_router/latest/go_router/GoRouter-class.html

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。
目录
相关文章
|
21天前
|
设计模式 前端开发 测试技术
Flutter 项目架构技术指南
探讨Flutter项目代码组织架构的关键方面和建议。了解设计原则SOLID、Clean Architecture,以及架构模式MVC、MVP、MVVM,如何有机结合使用,打造优秀的应用架构。
Flutter 项目架构技术指南
Doodle Jump — 使用Flutter&Flame开发游戏真不错!
用Flutter&Flame开发游戏是一种什么体验?最近网上冲浪的时候,我偶然发现了一个国外的游戏网站,类似于国内的4399。在浏览时,我遇到了一款经典的小游戏:Doodle Jump...
|
4天前
|
移动开发 前端开发 JavaScript
移动端 Hybrid 开发:RN、Flutter与Webview的抉择与融合
【4月更文挑战第6天】本文对比了移动端Hybrid开发的三种主流方案——React Native (RN),Flutter和Webview。RN基于JavaScript,适合React熟练的团队,适用于性能要求高、跨平台的中大型应用。Flutter,使用Dart语言,以其高性能和自定义UI适用于追求极致体验的项目。Webview适合快速移植Web应用至移动端,开发成本低但性能受限。选择时要考虑项目规模、性能需求、团队技术栈等因素,实际应用中常采用混合策略,如RN/Flutter+Webview、原生模块集成等,以实现最佳开发效果和长期技术规划。
19 0
|
30天前
|
开发框架 Dart 前端开发
构建响应式Web界面:Flutter的跨界前端技术
【2月更文挑战第23天】随着移动互联网的飞速发展,响应式Web设计成为现代前端开发的重要趋势。在众多框架中,Google推出的Flutter以其高效的渲染性能、跨平台能力及丰富的组件生态,为前端开发者带来了新的选择。本文将深入探讨如何利用Flutter进行高效、美观的响应式界面构建,同时剖析其与传统前端技术的差异和优势。
|
3月前
|
Web App开发 Ubuntu 应用服务中间件
Flutter笔记:Web支持原理与实践
Flutter笔记:Web支持原理与实践
98 0
|
3月前
|
Linux Android开发 iOS开发
Flutter笔记:滑块及其实现分析1
Flutter笔记:滑块及其实现分析1
90 0
|
3月前
|
Web App开发 JSON Android开发
Flutter笔记:获取设备信息
Flutter笔记:获取设备信息
111 0
|
3月前
|
容器
Flutter笔记:Box协议的布局约束原理与应用
Flutter笔记:Box协议的布局约束原理与应用
46 0
|
3月前
|
BI
Flutter笔记:路由观察者
Flutter笔记:路由观察者
73 0