Navigator — 是 Flutter 中的一个导航 widget 管理器,它通过 push、pop、pushReplacement 和 pushNamed 方法管理路由(Route)栈,用于在屏幕之间移动。与通过 State 直接替换 widget 不同,Navigator 在整屏级别工作:它存储过渡历史并支持平台动画。根据 Flutter API Reference (2026),Navigator 2.0(Router)为具有深度链接和自适应设计的复杂场景提供声明式导航管理。在典型应用中,Navigator 确保 Android 上"返回"按钮和 iOS 上滑动手势的正确行为。
要点
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 使用 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 方法接受一个 Route 并返回带有在 pop 时传递的结果的 Future。这允许从导航到的屏幕接收数据。例如,日期选择屏幕可以通过 Navigator.pop(context, selectedDate) 返回 DateTime。pop 方法无参数时返回 null,有参数时传递值给调用屏幕。
pushReplacement 用新 Route 替换当前 Route,从栈中移除当前 Route。这在用户不应返回上一屏幕的场景中至关重要。典型示例——登录屏幕:成功登录后,当前屏幕被主屏幕替换,"返回"按钮不会返回登录表单。
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_route 和 beamer。go_router 提供声明式 DSL 来定义路由,支持嵌套导航、重定向和深度链接,无需手动实现 RouterDelegate。根据 pub.dev (2026),go_router 在 35% 的偏好声明式方法的新 Flutter 项目中使用。
让我们看一个使用命名路由和屏幕间数据传输的 Navigator 示例。代码演示了产品列表屏幕、过渡到详细屏幕以及带结果返回。
// 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 — 带有 push 和 pop 方法的命令式 API,适用于简单的移动应用。Navigator 2.0 — 通过 Router、RouterDelegate 和 RouteInformationParser 的声明式 API,对于具有 URL 路由、深度链接和自适应导航的 Web 应用是必需的。对于实际项目,推荐使用 go_router 作为 Navigator 2.0 上的简化封装。
数据通过 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 — 是 Google 的声明式导航包,建立在 Navigator 2.0 之上。它提供简单的 DSL 来定义路由,支持嵌套、重定向、深度链接和用于 BottomNavigationBar 的 ShellRoute。在新项目中使用 go_router,特别是当需要 Web 支持或带有受保护路由的复杂导航模式时。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。