Navigator: Flutter 中的屏幕管理

作者: IT Sectr 发布日期: 2026-07-02 阅读时间: 9 分钟

Navigator — 是 Flutter 中的一个导航 widget 管理器,它通过 push、pop、pushReplacement 和 pushNamed 方法管理路由(Route)栈,用于在屏幕之间移动。与通过 State 直接替换 widget 不同,Navigator 在整屏级别工作:它存储过渡历史并支持平台动画。根据 Flutter API Reference (2026),Navigator 2.0(Router)为具有深度链接和自适应设计的复杂场景提供声明式导航管理。在典型应用中,Navigator 确保 Android 上"返回"按钮和 iOS 上滑动手势的正确行为。

要点

  • Navigator — 导航管理器,通过 push、pop、pushNamed、pushReplacement 和 pushAndRemoveUntil 管理路由栈
  • 路由栈 — Navigator 在 LIFO 栈中存储屏幕:每个 push 在顶部添加一个屏幕,pop 移除最顶部的
  • pushNamed — 通过 MaterialApp.routes 或 onGenerateRoute 中定义的命名路由进行导航
  • pushReplacement — 将当前屏幕替换为新屏幕,无法返回上一屏幕(例如登录后)
  • Navigator 2.0 — 用于 Web 和桌面导航的声明式 API,包含 Router、RouterDelegate 和 RouteInformationParser

Flutter 中的 Navigator 是什么

Navigator — 是一个 widget,管理 Route 对象栈并在 Flutter 应用中实现屏幕导航。每次 push 调用将新 Route 放置在栈顶,pop 移除顶部 Route 并返回上一屏幕。MaterialApp 自动为整个应用创建 Navigator,并通过 Navigator.of(context) 使其可访问。

与 StatefulWidget(内容替换通过单个 widget 内的 setState 发生)不同,Navigator 在具有自己生命周期的完整屏幕上操作。栈中的每个 Route 是带有自己 BuildContext 的隔离状态,防止内存泄漏并简化依赖项管理。当调用 pop 时,未使用的 Route 被销毁,释放资源。

根据 Flutter Navigation Guide (2026),Navigator 从命令式 API(Navigator 1.0)演进到声明式 API(Navigator 2.0)。Navigator 1.0 直接使用 push/pop 方法,适用于简单场景。Navigator 2.0(Router)适用于具有深度链接、自适应导航和 Web 路由的应用。

Navigator 内部工作原理

在内部,Navigator 使用 Overlay——一个特殊的 widget,一个叠一个地显示 Route。每个 Route 在 Overlay 中创建自己的位置,Z-index 对应栈中的深度。这解释了为什么在 push 时新屏幕在前一个之上动画显示,而在 pop 时前一个屏幕已经准备好显示:它没有被销毁,只是留在新屏幕下方的 Overlay 中。

对于过渡动画,Navigator 使用 PageTransitionsTheme,可以在 ThemeData 中覆盖。平台动画通过 CupertinoPageRoute(针对 iOS,从右侧滑入)和 MaterialPageRoute(针对 Android,从底部滑入)设置。Navigator 在使用 PlatformRoute 时自动选择合适的动画。

Navigator 提供一套管理 Route 栈的方法。每个方法解决特定的导航任务——从简单过渡到完全替换屏幕历史。让我们通过使用示例来查看主要方法。

方法描述应用场景
push在栈顶添加 Route进入新屏幕,可返回
pop从栈中移除顶部 Route返回上一屏幕
pushReplacement用新 Route 替换当前 Route登录后 — 登录屏幕替换为主屏幕
pushAndRemoveUntil添加 Route 并移除之前的直到条件清除历史记录后进入主屏幕
popUntil从栈中移除 Route 直到满足条件返回历史记录中的特定屏幕
maybePop仅当栈包含 >1 个 Route 时调用 pop防止意外按下时关闭应用

Push 和 Pop:基本操作

push 方法接受一个 Route 并返回带有在 pop 时传递的结果的 Future。这允许从导航到的屏幕接收数据。例如,日期选择屏幕可以通过 Navigator.pop(context, selectedDate) 返回 DateTime。pop 方法无参数时返回 null,有参数时传递值给调用屏幕。

PushReplacement:屏幕替换

pushReplacement 用新 Route 替换当前 Route,从栈中移除当前 Route。这在用户不应返回上一屏幕的场景中至关重要。典型示例——登录屏幕:成功登录后,当前屏幕被主屏幕替换,"返回"按钮不会返回登录表单。

命名路由和 onGenerateRoute

Navigator 支持通过 pushNamed 方法进行命名路由导航。开发人员不直接创建 Route,而是指定文本标识符,Navigator 根据 MaterialApp 中的配置自动创建 Route。这简化了代码并将路由定义集中在一个地方。

命名路由通过 MaterialApp 中的 routes 属性定义,其中每个键是路径字符串,值是返回 Widget 的函数。对于动态路由(带参数),使用 onGenerateRoute——一个接收 RouteSettings 并返回 Route 的回调。这允许通过 arguments 传递参数并实现深度导航。

根据 Flutter Cookbook (2026),通过 pushNamed 传递参数使用 arguments: Object? 参数。接收屏幕通过 ModalRoute.of(context)!.settings.arguments 提取参数,确保在没有全局变量或 InheritedWidget 的情况下进行类型安全的数据传输。

处理未知路由

MaterialApp 中的 onUnknownRoute 属性处理 pushNamed 被不存在的路由调用的情况。这对于显示 404 屏幕或重定向到主页非常有用。与 onGenerateRoute 结合,确保所有可能的导航场景的完全覆盖。

Navigator 2.0(也称为 Router API)——是 Flutter 2.0 中引入的声明式导航方法。与开发人员调用 push/pop 的命令式 Navigator 1.0 不同,Router 通过状态管理导航,自动将浏览器 URL 与当前屏幕同步。这对于 Web 应用和桌面版本尤为重要。

Navigator 2.0 架构由三个关键组件组成:RouteInformationParser 将 URL 解析为路由配置,RouterDelegate 将配置转换为 Route 列表,BackButtonDispatcher 处理系统"返回"按钮。这样的架构使导航完全可预测和可测试。

为简化与 Navigator 2.0 的工作,存在封装包:go_router(Google 推荐)、auto_routebeamer。go_router 提供声明式 DSL 来定义路由,支持嵌套导航、重定向和深度链接,无需手动实现 RouterDelegate。根据 pub.dev (2026),go_router 在 35% 的偏好声明式方法的新 Flutter 项目中使用。

让我们看一个使用命名路由和屏幕间数据传输的 Navigator 示例。代码演示了产品列表屏幕、过渡到详细屏幕以及带结果返回。

dart
// MaterialApp 中的路由配置
MaterialApp(
  initialRoute: '/',
  onGenerateRoute: (RouteSettings settings) {
    if (settings.name == '/') {
      return MaterialPageRoute(
        builder: (context) => const ProductListPage(),
      );
    }
    if (settings.name == '/product') {
      final productId = settings.arguments as String;
      return MaterialPageRoute(
        builder: (context) => ProductDetailPage(productId: productId),
      );
    }
    return MaterialPageRoute(
      builder: (context) => const NotFoundPage(),
    );
  },
)

// 带数据传输的导航
final result = await Navigator.pushNamed(
  context,
  '/product',
  arguments: 'product_42',
);

// 在接收屏幕上获取数据
final args = ModalRoute.of(context)!.settings.arguments as String;

// 登录后替换屏幕
Navigator.pushReplacementNamed(context, '/home');

// 清除栈到主屏幕
Navigator.pushNamedAndRemoveUntil(
  context,
  '/home',
  (route) => false,
);

在示例中,Navigator.pushNamed 将产品标识符传递给详细屏幕。通过 Navigator.pop(context, updatedProduct) 返回时,调用屏幕在 result 变量中接收更新的数据。pushReplacementNamed 在授权后替换当前屏幕,pushNamedAndRemoveUntil 使用条件 (route) => false 完全清除栈,阻止返回上一屏幕。

常见问题

Navigator 1.0 和 Navigator 2.0 的区别是什么?

Navigator 1.0 — 带有 push 和 pop 方法的命令式 API,适用于简单的移动应用。Navigator 2.0 — 通过 Router、RouterDelegate 和 RouteInformationParser 的声明式 API,对于具有 URL 路由、深度链接和自适应导航的 Web 应用是必需的。对于实际项目,推荐使用 go_router 作为 Navigator 2.0 上的简化封装。

如何通过 Navigator 在屏幕之间传输数据?

数据通过 pushNamed 中的 arguments 参数或直接通过 Route 构造函数传输。在接收屏幕上,数据通过 ModalRoute.of(context)!.settings.arguments 提取。要返回数据,使用 Navigator.pop(context, result) — 调用屏幕将结果作为 push 返回的 Future 值接收。

为什么"返回"按钮不返回上一屏幕?

如果当前屏幕通过 pushReplacement 打开,它会从栈中移除上一 Route。在这种情况下,没有导航历史,"返回"按钮将关闭应用。要返回,使用普通 push,而不是 pushReplacement。同时检查 Navigator.pop 调用在当前屏幕上是否被正确处理。

如何阻止返回上一屏幕?

使用 pushReplacement 将当前屏幕替换为新屏幕 — 上一屏幕从栈中移除,无法返回。要完全清除历史记录,使用带有条件 (route) => false 的 pushAndRemoveUntil。或者,您可以覆盖 WillPopScope(已弃用)或 PopScope 来拦截系统"返回"按钮。

什么是 go_router 以及何时使用它?

go_router — 是 Google 的声明式导航包,建立在 Navigator 2.0 之上。它提供简单的 DSL 来定义路由,支持嵌套、重定向、深度链接和用于 BottomNavigationBar 的 ShellRoute。在新项目中使用 go_router,特别是当需要 Web 支持或带有受保护路由的复杂导航模式时。

总结

  • Navigator — Flutter 导航管理器,使用 push、pop、pushReplacement 和 pushAndRemoveUntil 方法管理 Route 栈
  • LIFO 栈 — 每个 push 在顶部添加一个 Route,pop 移除最顶部的;栈按照"后进先出"原则存储过渡历史
  • pushReplacement — 替换当前屏幕无法返回,对登录和引导场景至关重要
  • 命名路由 — 使用 RouteSettings 和 onGenerateRoute 的 pushNamed 实现集中式路由定义和参数传递
  • Navigator 2.0 — 通过 Router、RouterDelegate 和 RouteInformationParser 实现声明式导航,用于 Web 深度链接
  • go_router — Google 推荐的 Navigator 2.0 封装,带有简单 DSL 和 ShellRoute 支持
  • 数据传输 — 通过 pushNamed 中的 arguments 和通过 Navigator.pop(context, value) 从 push 返回 Future 结果

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读