Flutter 路由导航完全指南
·
Flutter 路由导航完全指南
引言
路由导航是任何移动应用的核心功能之一。Flutter 提供了强大而灵活的路由系统,支持多种导航方式。本文将深入探讨 Flutter 路由导航的各种技巧和最佳实践。
基础导航
Navigator.push
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondPage()),
);
Navigator.pop
Navigator.pop(context);
高级技巧一:命名路由
注册命名路由
void main() {
runApp(MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => HomePage(),
'/detail': (context) => DetailPage(),
'/settings': (context) => SettingsPage(),
},
));
}
使用命名路由导航
Navigator.pushNamed(context, '/detail');
Navigator.pushReplacementNamed(context, '/settings');
Navigator.popUntil(context, ModalRoute.withName('/'));
高级技巧二:路由传参
基础参数传递
// 传递参数
Navigator.pushNamed(
context,
'/detail',
arguments: {'id': 1, 'name': 'Flutter'},
);
// 接收参数
final args = ModalRoute.of(context)?.settings.arguments as Map<String, dynamic>;
final id = args['id'];
final name = args['name'];
类型安全的参数传递
class DetailArguments {
final int id;
final String name;
DetailArguments({required this.id, required this.name});
}
// 传递
Navigator.pushNamed(
context,
'/detail',
arguments: DetailArguments(id: 1, name: 'Flutter'),
);
// 接收
final args = ModalRoute.of(context)?.settings.arguments as DetailArguments;
高级技巧三:路由动画
自定义页面过渡动画
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) => DetailPage(),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
const begin = Offset(1.0, 0.0);
const end = Offset.zero;
const curve = Curves.ease;
var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
return SlideTransition(
position: animation.drive(tween),
child: child,
);
},
),
);
使用 Hero 动画
// 源页面
Hero(
tag: 'imageHero',
child: Image.network('https://example.com/image.jpg'),
)
// 目标页面
Hero(
tag: 'imageHero',
child: Image.network('https://example.com/image.jpg'),
)
高级技巧四:嵌套导航
使用 Navigator 嵌套
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Navigator(
initialRoute: 'home',
onGenerateRoute: (settings) {
WidgetBuilder builder;
switch (settings.name) {
case 'home':
builder = (context) => HomeContent();
break;
case 'profile':
builder = (context) => ProfilePage();
break;
default:
throw Exception('Unknown route');
}
return MaterialPageRoute(builder: builder, settings: settings);
},
),
);
}
}
高级技巧五:路由守卫
使用 WillPopScope
WillPopScope(
onWillPop: () async {
// 询问用户是否确认退出
final shouldPop = await showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('确认退出'),
content: Text('确定要离开吗?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: Text('取消'),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: Text('确定'),
),
],
),
);
return shouldPop ?? false;
},
child: Scaffold(...),
)
高级技巧六:使用 GetX 路由
基本导航
// 跳转到新页面
Get.to(DetailPage());
// 跳转到新页面并移除之前的页面
Get.off(DetailPage());
// 跳转到新页面并移除所有之前的页面
Get.offAll(HomePage());
// 返回上一页
Get.back();
带参数导航
// 传递参数
Get.to(DetailPage(), arguments: {'id': 1, 'name': 'Flutter'});
// 在目标页面接收参数
final args = Get.arguments as Map<String, dynamic>;
路由别名
void main() {
runApp(GetMaterialApp(
initialRoute: '/',
getPages: [
GetPage(name: '/', page: () => HomePage()),
GetPage(name: '/detail', page: () => DetailPage()),
GetPage(name: '/settings', page: () => SettingsPage()),
],
));
}
// 使用别名导航
Get.toNamed('/detail');
Get.toNamed('/detail?id=1&name=Flutter');
实战案例:路由管理服务
class RouteService {
static const String home = '/';
static const String detail = '/detail';
static const String settings = '/settings';
static const String login = '/login';
static void goHome() => Get.offAllNamed(home);
static void goDetail({required int id}) => Get.toNamed('$detail?id=$id');
static void goSettings() => Get.toNamed(settings);
static void goLogin() => Get.offAllNamed(login);
}
// 使用
RouteService.goDetail(id: 1);
实战案例:认证路由守卫
class AuthMiddleware extends GetMiddleware {
@override
RouteSettings? redirect(String? route) {
final isLoggedIn = Get.find<AuthService>().isLoggedIn;
if (!isLoggedIn && route != RouteService.login) {
return RouteSettings(name: RouteService.login);
}
return null;
}
}
// 注册中间件
GetPage(
name: RouteService.settings,
page: () => SettingsPage(),
middlewares: [AuthMiddleware()],
)
实战案例:页面过渡动画
GetPage(
name: '/detail',
page: () => DetailPage(),
transition: Transition.fade,
transitionDuration: Duration(milliseconds: 500),
)
// 自定义过渡
GetPage(
name: '/detail',
page: () => DetailPage(),
customTransition: CustomTransition(
transitionBuilder: (context, animation, secondaryAnimation, child) {
return RotationTransition(
turns: animation,
child: child,
);
},
),
)
常见问题与解决方案
Q1:如何处理路由栈?
A:使用 Navigator.popUntil 或 Get.offAll:
Navigator.popUntil(context, ModalRoute.withName('/'));
Get.offAll(HomePage());
Q2:如何获取路由参数?
A:使用 ModalRoute.of(context)?.settings.arguments 或 Get.arguments:
final args = ModalRoute.of(context)?.settings.arguments;
final args = Get.arguments;
Q3:如何实现深度链接?
A:配置 Android 和 iOS 的 URL Scheme:
<!-- Android -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" />
</intent-filter>
最佳实践
1. 使用命名路由
// 错误:直接使用 MaterialPageRoute
Navigator.push(context, MaterialPageRoute(builder: (context) => DetailPage()));
// 正确:使用命名路由
Navigator.pushNamed(context, '/detail');
2. 封装路由服务
class Routes {
static const String home = '/';
static const String detail = '/detail';
}
3. 使用路由守卫保护页面
GetPage(
name: '/profile',
page: () => ProfilePage(),
middlewares: [AuthMiddleware()],
)
4. 统一过渡动画
GetMaterialApp(
defaultTransition: Transition.cupertino,
)
总结
路由导航是 Flutter 应用的核心功能。通过本文的学习,你应该能够:
- 掌握基本的导航方法
- 使用命名路由和参数传递
- 实现自定义页面过渡动画
- 使用路由守卫保护页面
- 利用 GetX 简化导航操作
选择合适的路由方案可以让应用更加清晰和可维护。
更多推荐
所有评论(0)