我来为你详细介绍Flutter中路由配置的各种方案,包括它们的特色、优缺点和实际代码示例。
1. 基础路由(MaterialApp.routes)
特色
- Flutter最基础的路由配置方式
- 适合简单的应用场景
- 配置简单直观
优缺点
优点 :简单易用,学习成本低 缺点:功能有限,不支持复杂路由场景
实际代码
dart
// main.dart
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '基础路由示例',
initialRoute: '/',
routes: {
'/': (context) => HomePage(),
'/details': (context) => DetailsPage(),
},
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('首页')),
body: Center(
child: ElevatedButton(
onPressed: () {
// 导航到详情页
Navigator.pushNamed(context, '/details');
},
child: Text('前往详情页'),
),
),
);
}
}
class DetailsPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('详情页')),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('返回'),
),
),
);
}
}
传参方式
基础路由不支持直接传参,需要通过ModalRoute获取参数:
dart
// 传参
Navigator.pushNamed(context, '/details', arguments: {
'id': 123,
'title': '示例标题'
});
// 获取参数
class DetailsPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final args = ModalRoute.of(context)!.settings.arguments as Map<String, dynamic>;
final id = args['id'];
final title = args['title'];
return Scaffold(
appBar: AppBar(title: Text(title)),
body: Center(
child: Text('ID: $id'),
),
);
}
}
2. onGenerateRoute(动态路由)
特色
- 支持动态路由生成
- 可以处理复杂的路由逻辑
- 支持参数验证和转换
优缺点
优点 :灵活性强,支持复杂路由逻辑 缺点:配置相对复杂
实际代码
dart
// main.dart
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '动态路由示例',
initialRoute: '/',
onGenerateRoute: (RouteSettings settings) {
switch (settings.name) {
case '/':
return MaterialPageRoute(builder: (context) => HomePage());
case '/details':
final args = settings.arguments as Map<String, dynamic>?;
return MaterialPageRoute(
builder: (context) => DetailsPage(
id: args?['id'] ?? 0,
title: args?['title'] ?? '默认标题',
),
);
case '/profile':
final userId = settings.arguments as String?;
return MaterialPageRoute(
builder: (context) => ProfilePage(userId: userId ?? 'unknown'),
);
default:
return MaterialPageRoute(
builder: (context) => NotFoundPage(routeName: settings.name ?? ''),
);
}
},
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('首页')),
body: Center(
child: Column(
children: [
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/details', arguments: {
'id': 123,
'title': '动态路由示例'
});
},
child: Text('前往详情页'),
),
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/profile', arguments: 'user123');
},
child: Text('前往个人主页'),
),
],
),
),
);
}
}
class DetailsPage extends StatelessWidget {
final int id;
final String title;
const DetailsPage({required this.id, required this.title});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(title)),
body: Center(
child: Column(
children: [
Text('ID: $id'),
Text('标题: $title'),
],
),
),
);
}
}
class ProfilePage extends StatelessWidget {
final String userId;
const ProfilePage({required this.userId});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('个人主页')),
body: Center(
child: Text('用户ID: $userId'),
),
);
}
}
class NotFoundPage extends StatelessWidget {
final String routeName;
const NotFoundPage({required this.routeName});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('页面未找到')),
body: Center(
child: Text('路由 "$routeName" 不存在'),
),
);
}
}
3. 命名路由(Named Routes)
特色
- 使用字符串标识路由
- 支持路由堆栈管理
- 适合中大型应用
优缺点
优点 :路由管理清晰,支持pushNamed、popUntil等操作 缺点:参数传递需要额外处理
实际代码
dart
// routes.dart
class AppRoutes {
static const String home = '/';
static const String details = '/details';
static const String profile = '/profile';
static const String settings = '/settings';
}
// main.dart
import 'package:flutter/material.dart';
import 'routes.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '命名路由示例',
initialRoute: AppRoutes.home,
routes: {
AppRoutes.home: (context) => HomePage(),
AppRoutes.details: (context) => DetailsPage(),
AppRoutes.profile: (context) => ProfilePage(),
AppRoutes.settings: (context) => SettingsPage(),
},
onGenerateRoute: (settings) {
// 处理未定义的路由
if (settings.name == '/unknown') {
return MaterialPageRoute(
builder: (context) => NotFoundPage(),
);
}
return null;
},
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('首页')),
body: Center(
child: Column(
children: [
ElevatedButton(
onPressed: () {
// 普通跳转
Navigator.pushNamed(context, AppRoutes.details);
},
child: Text('前往详情页'),
),
ElevatedButton(
onPressed: () {
// 替换当前路由
Navigator.pushReplacementNamed(context, AppRoutes.profile);
},
child: Text('替换到个人主页'),
),
ElevatedButton(
onPressed: () {
// 跳转并清除所有路由
Navigator.pushNamedAndRemoveUntil(
context,
AppRoutes.settings,
(route) => false,
);
},
child: Text('跳转到设置页(清除堆栈)'),
),
],
),
),
);
}
}
class DetailsPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('详情页')),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('返回'),
),
),
);
}
}
class ProfilePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('个人主页')),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('返回'),
),
),
);
}
}
class SettingsPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('设置页')),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('返回'),
),
),
);
}
}
class NotFoundPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('页面未找到')),
body: Center(
child: Text('页面不存在'),
),
);
}
}
4. 第三方路由库(go_router)
特色
- 声明式路由管理
- 支持深度链接
- 强大的路由守卫
优缺点
优点 :功能强大,支持复杂路由场景 缺点:需要学习第三方库
实际代码
首先添加依赖:
yaml
# pubspec.yaml
dependencies:
go_router: ^14.0.0
dart
// main.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final GoRouter _router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => HomePage(),
routes: [
GoRoute(
path: 'details/:id',
builder: (context, state) {
final id = state.pathParameters['id']!;
final title = state.uri.queryParameters['title'] ?? '默认标题';
return DetailsPage(id: int.parse(id), title: title);
},
),
GoRoute(
path: 'profile',
builder: (context, state) => ProfilePage(),
),
],
),
],
errorBuilder: (context, state) => NotFoundPage(),
);
@override
Widget build(BuildContext context) {
return MaterialApp.router(
title: 'GoRouter示例',
routerConfig: _router,
);
}
}
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/123?title=GoRouter示例');
},
child: Text('前往详情页'),
),
ElevatedButton(
onPressed: () {
// 相对路径
context.go('/profile');
},
child: Text('前往个人主页'),
),
ElevatedButton(
onPressed: () {
// 传递额外参数
context.go('/details/456', extra: {'from': 'home'});
},
child: Text('带额外参数跳转'),
),
],
),
),
);
}
}
class DetailsPage extends StatelessWidget {
final int id;
final String title;
const DetailsPage({required this.id, required this.title});
@override
Widget build(BuildContext context) {
final extra = GoRouterState.of(context).extra as Map<String, dynamic>?;
return Scaffold(
appBar: AppBar(title: Text(title)),
body: Center(
child: Column(
children: [
Text('ID: $id'),
Text('标题: $title'),
if (extra != null) Text('来源: ${extra['from']}'),
ElevatedButton(
onPressed: () {
context.pop();
},
child: Text('返回'),
),
],
),
),
);
}
}
class ProfilePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('个人主页')),
body: Center(
child: ElevatedButton(
onPressed: () {
context.pop();
},
child: Text('返回'),
),
),
);
}
}
class NotFoundPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('页面未找到')),
body: Center(
child: Text('页面不存在'),
),
);
}
}
5. 自定义路由管理器
特色
- 完全自定义控制
- 适合特殊需求
- 高度灵活
优缺点
优点 :完全控制路由逻辑 缺点:开发成本高
实际代码
dart
// custom_router.dart
import 'package:flutter/material.dart';
class CustomRouteManager {
static final CustomRouteManager _instance = CustomRouteManager._internal();
factory CustomRouteManager() => _instance;
CustomRouteManager._internal();
final Map<String, WidgetBuilder> _routes = {};
final Map<String, Route<dynamic> Function(RouteSettings)> _routeFactories = {};
void registerRoute(String path, WidgetBuilder builder) {
_routes[path] = builder;
}
void registerRouteFactory(String path,
Route<dynamic> Function(RouteSettings) factory) {
_routeFactories[path] = factory;
}
Route<dynamic>? generateRoute(RouteSettings settings) {
// 优先使用路由工厂
if (_routeFactories.containsKey(settings.name)) {
return _routeFactories[settings.name]!(settings);
}
// 使用普通路由
if (_routes.containsKey(settings.name)) {
return MaterialPageRoute(
builder: _routes[settings.name]!,
settings: settings,
);
}
return null;
}
void navigateTo(BuildContext context, String path,
{Map<String, dynamic>? arguments}) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => _buildPage(path, arguments),
),
);
}
Widget _buildPage(String path, Map<String, dynamic>? arguments) {
if (_routes.containsKey(path)) {
return _routes[path]!(BuildContext(null));
}
return NotFoundPage(routeName: path);
}
}
// main.dart
import 'package:flutter/material.dart';
import 'custom_router.dart';
void main() {
// 注册路由
final router = CustomRouteManager();
router.registerRoute('/', (context) => HomePage());
router.registerRoute('/details', (context) => DetailsPage());
runApp(MyApp(router: router));
}
class MyApp extends StatelessWidget {
final CustomRouteManager router;
const MyApp({required this.router});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '自定义路由示例',
home: HomePage(),
onGenerateRoute: router.generateRoute,
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('首页')),
body: Center(
child: ElevatedButton(
onPressed: () {
CustomRouteManager().navigateTo(context, '/details',
arguments: {'id': 123, 'title': '自定义路由'});
},
child: Text('前往详情页'),
),
),
);
}
}
class DetailsPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('详情页')),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('返回'),
),
),
);
}
}
class NotFoundPage extends StatelessWidget {
final String routeName;
const NotFoundPage({required this.routeName});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('页面未找到')),
body: Center(
child: Text('路由 "$routeName" 不存在'),
),
);
}
}
总结对比
方案 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
基础路由 | 简单应用 | 简单易用 | 功能有限 |
动态路由 | 中等复杂度 | 灵活性强 | 配置复杂 |
命名路由 | 中大型应用 | 管理清晰 | 参数处理麻烦 |
go_router | 复杂应用 | 功能强大 | 学习成本高 |
自定义路由 | 特殊需求 | 完全控制 | 开发成本高 |
参数传递方式总结
- 路径参数 :
/user/123
→state.pathParameters['id']
- 查询参数 :
/user?id=123
→state.uri.queryParameters['id']
- 额外参数 :
arguments
属性 →ModalRoute.of(context)!.settings.arguments
- 构造函数传参:最推荐的方式,类型安全
选择哪种方案取决于你的应用复杂度、团队熟悉度和具体需求。对于大多数应用,推荐使用onGenerateRoute
或go_router
。