跳到主内容

导航与路由

Flutter 导航与路由功能概览

Flutter 提供了一套完整的系统,用于在不同屏幕间导航并处理深层链接(Deep Links)。对于没有复杂深层链接需求的小型应用,可以使用 Navigator;而对于有特定深层链接和导航需求的应用,则应同时使用 Router,以便在 Android 和 iOS 上正确处理深层链接,并在 Web 应用运行时与地址栏保持同步。

如需配置 Android 或 iOS 应用以处理深层链接,请参阅 深层链接

使用 Navigator

#

Navigator 组件使用堆栈(Stack)来显示屏幕,并为目标平台使用适当的过渡动画。要导航到新屏幕,可通过路由的 BuildContext 访问 Navigator,并调用 push()pop() 等命令式方法。

dart
child: const Text('Open second screen'),
onPressed: () {
  Navigator.of(context).push(
    MaterialPageRoute<void>(
      builder: (context) => const SecondScreen(),
    ),
  );
},

由于 Navigator 维护了一个 Route 对象堆栈(代表历史堆栈),push() 方法还需要接收一个 Route 对象。MaterialPageRoute 对象是 Route 的子类,它指定了 Material Design 的过渡动画。有关如何使用 Navigator 的更多示例,请遵循 Flutter Cookbook 中的 导航方案 或访问 Navigator API 文档

使用命名路由

#

对于导航和深层链接需求简单的应用,可以使用 Navigator 进行导航,并使用 MaterialApp.routes 参数来处理深层链接。

dart
child: const Text('Open second screen'),
onPressed: () {
  Navigator.pushNamed(context, '/second');
},

/second 表示在 MaterialApp.routes 列表中声明的命名路由。如需完整示例,请遵循 Flutter Cookbook 中的 使用命名路由导航 方案。

局限性

#

尽管命名路由可以处理深层链接,但其行为是固定的,无法自定义。当平台收到新的深层链接时,无论用户当前身处何处,Flutter 都会向 Navigator 推入一个新 Route

此外,Flutter 也不支持对使用命名路由的应用使用浏览器的“前进”按钮。出于这些原因,我们不建议在大多数应用中使用命名路由。建议改用像 go_router 这样的路由包,或结合使用 NavigatorMaterialPageRoute

使用 Router

#

对于具有高级导航和路由需求(例如使用直接链接到每个屏幕的 Web 应用,或包含多个 Navigator 组件的应用)的 Flutter 应用,应使用诸如 go_router 之类的路由包。当应用接收到新的深层链接时,它可以解析路由路径并配置 Navigator

要使用 Router,请切换至 MaterialAppCupertinoApprouter 构造函数,并为其提供 Router 配置。诸如 go_router 之类的路由包通常会提供路由配置,路由的使用方式如下:

dart
child: const Text('Open second screen'),
onPressed: () => context.go('/second'),

由于像 go_router 这样的包是声明式的,因此当接收到深层链接时,它们总是会显示相同的屏幕。

同时使用 Router 和 Navigator

#

RouterNavigator 是为了协同工作而设计的。您可以通过声明式路由包(如 go_router)使用 Router API 进行导航,也可以通过在 Navigator 上调用 push()pop() 等命令式方法进行导航。

当您使用 Router 或声明式路由包进行导航时,Navigator 上的每个路由都是页面支持的(page-backed),这意味着它是使用 Navigator 构造函数上的 pages 参数从 Page 创建的。相反,通过调用 Navigator.pushshowDialog 创建的任何 Route 都会向 Navigator 添加一个无页面(pageless)路由。如果您正在使用路由包,页面支持的路由总是可以被深层链接,而无页面路由则不能。

当一个页面支持的 RouteNavigator 中移除时,其后所有的无页面路由也会被移除。例如,如果深层链接通过从 Navigator 移除一个页面支持的路由来进行导航,那么其后(直到下一个页面支持的路由为止)所有的无页面路由也会被移除。

Web 支持

#

使用 Router 类的应用会与浏览器的 History API 集成,从而在使用浏览器的“后退”和“前进”按钮时提供一致的体验。每当您使用 Router 进行导航时,浏览器历史堆栈中都会添加一个 History API 条目。按下后退按钮会使用逆向时间顺序导航,这意味着用户会被带回到之前使用 Router 显示的位置。这意味着,如果用户从 Navigator 中弹出一个页面,然后按下浏览器后退按钮,则之前的页面会被重新推入堆栈。

更多信息

#

有关导航和路由的更多信息,请查阅以下资源:

  • Flutter Cookbook 包含了多个导航方案,展示了如何使用 Navigator
  • NavigatorRouter API 文档中包含了关于如何在不使用路由包的情况下设置声明式导航的详细信息。
  • 理解导航(Material Design 文档中的页面)概述了设计应用导航的概念,包括对前进、向上和时间顺序导航的解释。
  • 学习 Flutter 的新导航与路由系统(Medium 文章)介绍了如何在不使用路由包的情况下直接使用 Router 组件。
  • Router 设计文档包含了 Router API 的设计动机和实现方案。