Flutter第三方路由管理包详解
路由管理是Flutter应用开发中的核心功能。除了Flutter自带的路由系统,第三方路由包提供了更强大、便捷的功能。以下是目前流行的第三方路由管理包及其详细使用指南。
1. GetX路由管理
简介
GetX是一个轻量级但功能强大的Flutter包,除了路由管理还包含状态管理和依赖注入。
安装
yaml
dependencies:
get: ^4.6.5
基本使用
dart
import 'package:get/get.dart';
// 主函数
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetMaterialApp(
// 使用GetMaterialApp替代MaterialApp
title: 'GetX路由示例',
initialRoute: '/',
getPages: [
GetPage(name: '/', page: () => HomePage()),
GetPage(name: '/details', page: () => DetailsPage()),
GetPage(
name: '/profile/:userId',
page: () => ProfilePage(),
),
],
);
}
}
// 页面定义
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('首页')),
body: Center(
child: Column(
children: [
ElevatedButton(
onPressed: () {
// 普通跳转
Get.to(() => DetailsPage());
},
child: Text('跳转到详情页'),
),
ElevatedButton(
onPressed: () {
// 命名路由跳转
Get.toNamed('/details');
},
child: Text('命名路由跳转'),
),
ElevatedButton(
onPressed: () {
// 带参数跳转
Get.toNamed('/profile/123');
},
child: Text('带参数跳转'),
),
ElevatedButton(
onPressed: () {
// 返回并带结果
Get.back(result: '返回的数据');
},
child: Text('返回'),
),
ElevatedButton(
onPressed: () {
// 替换当前路由
Get.off(() => DetailsPage());
},
child: Text('替换路由'),
),
ElevatedButton(
onPressed: () {
// 清空路由栈并跳转
Get.offAll(() => DetailsPage());
},
child: Text('清空栈并跳转'),
),
],
),
),
);
}
}
// 详情页
class DetailsPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('详情页')),
body: Center(
child: Column(
children: [
Text('详情页内容'),
ElevatedButton(
onPressed: () {
// 返回并带参数
Get.back(result: '详情页返回');
},
child: Text('返回首页'),
),
],
),
),
);
}
}
// 带参数的页面
class ProfilePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 获取路由参数
final userId = Get.parameters['userId'];
return Scaffold(
appBar: AppBar(title: Text('用户资料: $userId')),
body: Center(
child: Text('用户ID: $userId'),
),
);
}
}
高级功能
dart
// 1. 中间件(路由守卫)
class AuthMiddleware extends GetMiddleware {
@override
RouteSettings? redirect(String? route) {
// 检查用户是否登录
bool isLoggedIn = false; // 这里替换为实际的登录检查
if (!isLoggedIn && route == '/profile') {
// 未登录,重定向到登录页
return RouteSettings(name: '/login');
}
return null;
}
@override
GetPage? onPageCalled(GetPage? page) {
print('路由被调用: ${page?.name}');
return super.onPageCalled(page);
}
}
// 在路由配置中使用中间件
getPages: [
GetPage(
name: '/profile',
page: () => ProfilePage(),
middlewares: [AuthMiddleware()],
),
];
// 2. 传参的多种方式
// 方式一:URL参数
Get.toNamed('/profile/123');
// 方式二:参数对象
Get.toNamed('/profile', arguments: {
'userId': '123',
'name': '张三'
});
// 在目标页面获取参数
class ProfilePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final arguments = Get.arguments; // 获取传递的参数
return Scaffold(
appBar: AppBar(
title: Text(arguments['name'] ?? '用户资料'),
),
body: Center(
child: Text('用户ID: ${arguments['userId']}'),
),
);
}
}
// 3. 路由观察者
Get.config(
enableLog: true,
logWriterCallback: (text, {bool isError = false}) {
print('路由日志: $text');
},
);
路由动画
dart
// 自定义转场动画
Get.to(
DetailsPage(),
transition: Transition.fadeIn, // 渐变
duration: Duration(milliseconds: 300),
);
// 更多动画类型
Get.to(
DetailsPage(),
transition: Transition.cupertino, // iOS风格
);
Get.to(
DetailsPage(),
transition: Transition.zoom, // 缩放
);
Get.to(
DetailsPage(),
transition: Transition.downToUp, // 从下往上
);
// 自定义动画
Get.to(
DetailsPage(),
transition: Transition.circularReveal, // 圆形展开
curve: Curves.easeInOut,
duration: Duration(milliseconds: 500),
);
2. Auto Route
简介
基于代码生成的路由管理,类型安全,支持嵌套路由、守卫等。
安装
yaml
dependencies:
auto_route: ^7.2.0
dev_dependencies:
auto_route_generator: ^7.2.0
build_runner: ^2.3.0
基本使用
dart
// 1. 创建路由配置
// app_router.dart
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
part 'app_router.gr.dart';
@MaterialAutoRouter(
replaceInRouteName: 'Page,Route',
routes: <AutoRoute>[
AutoRoute(page: HomePage, initial: true),
AutoRoute(page: DetailsPage),
AutoRoute(page: ProfilePage, path: '/profile/:userId'),
AutoRoute(
page: SettingsPage,
children: [
AutoRoute(page: AccountPage, initial: true),
AutoRoute(page: NotificationPage),
AutoRoute(page: PrivacyPage),
],
),
],
)
class AppRouter extends _$AppRouter {}
// 2. 生成路由代码
// 运行命令:flutter packages pub run build_runner build
// 3. 在main.dart中使用
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final _appRouter = AppRouter();
@override
Widget build(BuildContext context) {
return MaterialApp.router(
title: 'AutoRoute示例',
routerDelegate: _appRouter.delegate(),
routeInformationParser: _appRouter.defaultRouteParser(),
);
}
}
// 4. 页面定义
@RoutePage()
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('首页')),
body: Center(
child: Column(
children: [
ElevatedButton(
onPressed: () {
context.pushRoute(DetailsRoute());
},
child: Text('跳转到详情'),
),
ElevatedButton(
onPressed: () {
context.pushRoute(ProfileRoute(userId: '123'));
},
child: Text('用户资料'),
),
ElevatedButton(
onPressed: () {
context.pushRoute(SettingsRoute());
},
child: Text('设置(嵌套路由)'),
),
],
),
),
);
}
}
// 5. 带参数的页面
@RoutePage()
class ProfilePage extends StatelessWidget {
final String userId;
const ProfilePage({
@PathParam('userId') required this.userId,
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('用户: $userId')),
body: Center(
child: Text('用户ID: $userId'),
),
);
}
}
// 6. 查询参数
@RoutePage()
class SearchPage extends StatelessWidget {
final String? query;
const SearchPage({
@QueryParam('q') this.query,
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('搜索')),
body: Center(
child: Text('搜索词: ${query ?? "无"}'),
),
);
}
}
// 跳转时传递查询参数
context.pushRoute(SearchRoute(queryParams: {'q': 'flutter'}));
路由守卫
dart
// 1. 创建守卫
class AuthGuard extends AutoRouteGuard {
@override
void onNavigation(NavigationResolver resolver, StackRouter router) {
bool isAuthenticated = false; // 检查登录状态
if (isAuthenticated) {
resolver.next(true); // 允许导航
} else {
// 重定向到登录页
router.push(LoginRoute(
onLoginResult: (success) {
if (success) {
resolver.next(true);
} else {
resolver.next(false);
}
},
));
}
}
}
// 2. 在路由配置中使用守卫
@MaterialAutoRouter(
replaceInRouteName: 'Page,Route',
routes: [
AutoRoute(page: HomePage, initial: true),
AutoRoute(
page: DashboardPage,
guards: [AuthGuard()], // 应用守卫
),
],
)
class AppRouter extends _$AppRouter {}
嵌套路由
dart
// 1. 主页面结构
@RoutePage()
class MainPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AutoTabsScaffold(
routes: [
HomeRoute(),
SearchRoute(),
ProfileRoute(),
],
bottomNavigationBuilder: (_, tabsRouter) {
return BottomNavigationBar(
currentIndex: tabsRouter.activeIndex,
onTap: tabsRouter.setActiveIndex,
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'),
BottomNavigationBarItem(icon: Icon(Icons.search), label: '搜索'),
BottomNavigationBarItem(icon: Icon(Icons.person), label: '我的'),
],
);
},
);
}
}
3. Fluro
简介
功能丰富的路由框架,支持通配符、参数传递、中间件等。
安装
yaml
dependencies:
fluro: ^2.0.5
基本使用
dart
import 'package:flutter/material.dart';
import 'package:fluro/fluro.dart';
// 1. 创建路由器实例
final router = FluroRouter();
// 2. 定义路由处理器
void defineRoutes() {
// 首页
router.define(
'/',
handler: Handler(
handlerFunc: (context, parameters) {
return HomePage();
},
),
);
// 详情页
router.define(
'/details',
handler: Handler(
handlerFunc: (context, parameters) {
return DetailsPage();
},
),
);
// 带参数的页面
router.define(
'/user/:id',
handler: Handler(
handlerFunc: (context, parameters) {
String id = parameters['id']?.first ?? '';
return UserPage(userId: id);
},
),
);
// 可选参数
router.define(
'/search',
handler: Handler(
handlerFunc: (context, parameters) {
String? query = parameters['q']?.first;
return SearchPage(query: query);
},
),
);
// 通配符路由
router.define(
'/settings/*',
handler: Handler(
handlerFunc: (context, parameters) {
List<String>? path = parameters['*'];
return SettingsPage(path: path);
},
),
);
}
// 3. 在应用中使用
class MyApp extends StatelessWidget {
MyApp() {
defineRoutes();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fluro示例',
onGenerateRoute: router.generator,
initialRoute: '/',
);
}
}
// 4. 页面导航
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('首页')),
body: Center(
child: Column(
children: [
ElevatedButton(
onPressed: () {
// 跳转到详情页
router.navigateTo(context, '/details');
},
child: Text('详情页'),
),
ElevatedButton(
onPressed: () {
// 带参数跳转
router.navigateTo(
context,
'/user/123',
transition: TransitionType.cupertino,
);
},
child: Text('用户页'),
),
ElevatedButton(
onPressed: () {
// 带查询参数跳转
router.navigateTo(
context,
'/search?q=flutter',
);
},
child: Text('搜索页'),
),
ElevatedButton(
onPressed: () {
// 替换路由
router.navigateTo(
context,
'/details',
replace: true,
);
},
child: Text('替换路由'),
),
ElevatedButton(
onPressed: () {
// 清空栈
router.navigateTo(
context,
'/details',
clearStack: true,
);
},
child: Text('清空栈跳转'),
),
],
),
),
);
}
}
// 5. 中间件示例
class AuthMiddleware extends Handler {
@override
Future<bool> handle(
BuildContext context,
Map<String, List<String>> parameters,
RouteMatch match,
) async {
bool isLoggedIn = false; // 检查登录状态
if (!isLoggedIn && match.route.path == '/profile') {
// 重定向到登录页
router.navigateTo(context, '/login');
return false;
}
return true;
}
}
4. Go Router
简介
官方推荐的声明式路由包,支持Web和移动端。
安装
yaml
dependencies:
go_router: ^10.0.0
基本使用
dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
// 1. 创建路由配置
final GoRouter router = GoRouter(
routes: [
// 首页
GoRoute(
path: '/',
builder: (context, state) => HomePage(),
),
// 详情页
GoRoute(
path: '/details',
builder: (context, state) => DetailsPage(),
),
// 带参数的页面
GoRoute(
path: '/user/:id',
builder: (context, state) {
String id = state.params['id']!;
return UserPage(userId: id);
},
),
// 查询参数
GoRoute(
path: '/search',
builder: (context, state) {
String? query = state.queryParams['q'];
return SearchPage(query: query);
},
),
// 嵌套路由
ShellRoute(
builder: (context, state, child) {
return MainLayout(child: child);
},
routes: [
GoRoute(
path: '/dashboard',
builder: (context, state) => DashboardPage(),
routes: [
GoRoute(
path: 'settings',
builder: (context, state) => SettingsPage(),
),
],
),
],
),
],
// 错误页面
errorBuilder: (context, state) => ErrorPage(error: state.error),
// 重定向
redirect: (context, state) {
bool isLoggedIn = false;
// 检查是否访问需要登录的页面
if (state.location.startsWith('/profile') && !isLoggedIn) {
return '/login';
}
return null;
},
);
// 2. 在应用中使用
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp.router(
title: 'GoRouter示例',
routerConfig: router,
);
}
}
// 3. 页面导航
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('首页')),
body: Center(
child: Column(
children: [
ElevatedButton(
onPressed: () {
context.go('/details');
},
child: Text('跳转到详情页'),
),
ElevatedButton(
onPressed: () {
context.go('/user/123');
},
child: Text('用户资料'),
),
ElevatedButton(
onPressed: () {
context.go('/search?q=flutter');
},
child: Text('搜索'),
),
ElevatedButton(
onPressed: () {
context.go('/dashboard');
},
child: Text('仪表板(嵌套路由)'),
),
ElevatedButton(
onPressed: () {
// 替换当前路由
context.replace('/details');
},
child: Text('替换路由'),
),
],
),
),
);
}
}
// 4. 路由观察者
final GoRouter router = GoRouter(
routes: [...],
observers: [
MyRouteObserver(),
],
);
class MyRouteObserver extends NavigatorObserver {
@override
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
print('路由入栈: ${route.settings.name}');
}
@override
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
print('路由出栈: ${route.settings.name}');
}
}
5. 路由包对比与选择建议
| 特性 | GetX | AutoRoute | Fluro | GoRouter |
|---|---|---|---|---|
| 学习曲线 | 简单 | 中等 | 中等 | 简单 |
| 类型安全 | 否 | 是 | 否 | 是 |
| 代码生成 | 否 | 是 | 否 | 否 |
| Web支持 | 是 | 是 | 是 | 优秀 |
| 嵌套路由 | 支持 | 优秀 | 支持 | 优秀 |
| 路由守卫 | 支持 | 支持 | 支持 | 支持 |
| 参数传递 | 多种方式 | 类型安全 | URL参数 | 类型安全 |
| 社区活跃 | 非常活跃 | 活跃 | 一般 | 非常活跃 |
| 维护状态 | 活跃 | 活跃 | 维护中 | 官方维护 |
选择建议
- 新手/快速开发 :推荐 GetX,学习成本低,功能全面
- 大型项目/团队协作 :推荐 AutoRoute,类型安全,维护性好
- Web项目 :推荐 GoRouter,官方维护,Web支持最好
- 已有项目迁移:如果已有Fluro项目可继续使用
6. 实际项目最佳实践
统一路由管理
dart
// routes.dart - 统一管理路由
class Routes {
static const String home = '/';
static const String details = '/details';
static const String profile = '/profile/:id';
static const String settings = '/settings';
static const String login = '/login';
// 获取路径
static String profilePath(String id) => '/profile/$id';
// 命名路由映射
static Map<String, WidgetBuilder> getRoutes() {
return {
home: (context) => HomePage(),
details: (context) => DetailsPage(),
login: (context) => LoginPage(),
};
}
}
路由工具类
dart
// router_utils.dart
class RouterUtils {
// 统一跳转方法
static void navigateTo(BuildContext context, String path, {
Map<String, String>? params,
Map<String, dynamic>? arguments,
bool replace = false,
}) {
if (replace) {
Navigator.pushReplacementNamed(context, path, arguments: arguments);
} else {
Navigator.pushNamed(context, path, arguments: arguments);
}
}
// 带返回结果的跳转
static Future<T?> navigateForResult<T>(
BuildContext context,
String path, {
Map<String, dynamic>? arguments,
}) async {
return await Navigator.pushNamed(
context,
path,
arguments: arguments,
);
}
// 清空栈跳转
static void navigateAndClearStack(
BuildContext context,
String path, {
Map<String, dynamic>? arguments,
}) {
Navigator.pushNamedAndRemoveUntil(
context,
path,
(route) => false,
arguments: arguments,
);
}
}
状态管理与路由结合
dart
// 使用Provider + 路由
class AppState extends ChangeNotifier {
String? _authToken;
String? get authToken => _authToken;
void setAuthToken(String token) {
_authToken = token;
notifyListeners();
}
void logout() {
_authToken = null;
notifyListeners();
}
}
// 路由守卫
class AuthGuard extends GetMiddleware {
@override
RouteSettings? redirect(String? route) {
final appState = Get.find<AppState>();
if (!_isPublicRoute(route) && appState.authToken == null) {
return RouteSettings(name: Routes.login);
}
return null;
}
bool _isPublicRoute(String? route) {
final publicRoutes = [Routes.login, Routes.register];
return publicRoutes.contains(route);
}
}
总结
第三方路由包各有优势,选择取决于项目需求:
- GetX:适合快速开发,功能全面
- AutoRoute:适合大型项目,类型安全
- Fluro:功能丰富,灵活
- GoRouter:官方推荐,Web支持好
无论选择哪个包,都应保持路由管理的统一性和规范性,遵循最佳实践,确保应用的可维护性和扩展性。