简介
导航是应用程序中不可或缺的功能,Flutter 提供了简单而强大的导航 API。本文介绍 Flutter 中最基本的导航方法。
基本导航
页面跳转
// 跳转到新页面
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondPage(),
),
);
// 返回上一页
Navigator.pop(context);
带返回值的导航
// 跳转并等待返回值
final result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SelectionPage(),
),
);
// 返回并传值
Navigator.pop(context, 'selected value');
路由动画
自定义转场动画
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) => SecondPage(),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: child,
);
},
),
);
常用转场效果
// 淡入淡出
FadeTransition(
opacity: animation,
child: child,
);
// 缩放
ScaleTransition(
scale: animation,
child: child,
);
// 旋转
RotationTransition(
turns: animation,
child: child,
);
完整示例
class NavigationDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Navigation Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () => _navigateToSecondPage(context),
child: Text('Go to Second Page'),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () => _navigateAndWaitForResult(context),
child: Text('Select an Option'),
),
],
),
),
);
}
Future<void> _navigateToSecondPage(BuildContext context) async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondPage(),
),
);
}
Future<void> _navigateAndWaitForResult(BuildContext context) async {
final result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SelectionPage(),
),
);
if (result != null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Selected: $result')),
);
}
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Page'),
),
body: Center(
child: ElevatedButton(
onPressed: () => Navigator.pop(context),
child: Text('Go Back'),
),
),
);
}
}
class SelectionPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Make a Selection'),
),
body: ListView(
children: [
ListTile(
title: Text('Option 1'),
onTap: () => Navigator.pop(context, 'Option 1'),
),
ListTile(
title: Text('Option 2'),
onTap: () => Navigator.pop(context, 'Option 2'),
),
ListTile(
title: Text('Option 3'),
onTap: () => Navigator.pop(context, 'Option 3'),
),
],
),
);
}
}
最佳实践
- 登录成功用 Get.offNamed:
Get.offNamed(RouteNames.main)把登录页从栈里清掉——用 toNamed 的话,用户按返回键会回到登录页,这是登录流程的经典 bug - 退出登录用 Get.offAllNamed:清掉整个路由栈,并配合清掉登录态 controller,防止切账号后看到旧数据
- 需要返回值的页面用 await:
final result = await Get.to(() => EditPage()),编辑页Get.back(result: data)——表单回填、选择器回传都靠这个,别用全局变量传 - controller 里直接跳:GetX 跳转不依赖 context,网络回调/定时器里
Get.toNamed直接调——这是作者从 Navigator 切 GetX 的主要爽点
注意事项
- 路由栈别超过 5 层:详情→评论→用户主页→关注列表……无限 push,内存涨、返回键要按十几次;深层级用 offNamed 替换而不是 push
- 根页面调 Get.back() 会直接退出 App:退出前用 PopScope/WillPopScope 做”再按一次退出”确认,别让用户误触就闪退
- 转场动画别覆盖 iOS 边缘右滑返回手势:自定义转场和原生返回手势冲突,测试机上偶现卡死(自定义动画篇的坑)——业务 App 默认转场就够了
- 跳转前判空:
if (id == null) return;再跳详情页——空 id 的详情页除了展示”加载失败”没有任何意义
实战案例
我的货运项目 某物流冷链项目 里,页面跳转全走 GetX,不用原生 Navigator。最常用的就两行:Get.toNamed(RouteNames.idCardVerify) 跳身份证认证页,Get.to(() => const CustomServicePage()) 跳客服页。前者是命名路由,后者是直接传 widget——我混着用:需要深链接/统一管理的走命名,需要临时弹个页面的直接传 widget。GetX 的好处是跳转不用传 context,在 controller 里(比如网络请求回调里)直接 Get.toNamed 就行,这点比 Navigator 爽很多。但代价是路由表要集中维护,我单独搞了个 RouteNames 类全放 static const,getPages: RoutePages.list 统一注册,不然字符串满天飞,改名就是灾难。
总结
基础导航是 Flutter 应用开发中的重要组成部分。通过合理使用 Navigator 的 push 和 pop 方法,可以实现流畅的页面跳转效果。掌握基础导航对于开发高质量的 Flutter 应用至关重要。
