自己学习的小demo地址放在这里,仅供学习参考,flutter学习demo
在 Flutter 中封装一个 Router.dart
文件来统一管理页面跳转是一个非常实用的做法,可以提升代码的可维护性和复用性。下面我将为你提供一个结构清晰、功能全面的 Router
类封装示例,并附上使用说明。
✅ 1. 创建 Router.dart
文件
// lib/router/router.dart
import 'package:flutter/material.dart';
class Router {
// 路由表:定义所有页面的路由路径与对应的构建器
static final Map<String, WidgetBuilder> routeTable = {
'/': (context) => const HomeScreen(),
'/detail': (context) => DetailScreen(
arguments: ModalRoute.of(context)!.settings.arguments as String),
'/settings': (context) => const SettingsScreen(),
};
// 页面跳转(带返回按钮)
static Future<T?> pushNamed<T extends Object?>(
BuildContext context,
String routeName, {
Object? arguments,
}) {
return Navigator.pushNamed<T>(
context,
routeName,
arguments: arguments,
);
}
// 页面跳转并替换当前页面(无返回按钮)
static Future<T?> pushReplacementNamed<T extends Object?>(
BuildContext context,
String routeName, {
Object? arguments,
}) {
return Navigator.pushReplacementNamed<T, Object?>(
context,
routeName,
arguments: arguments,
);
}
// 弹出当前页面(返回上一页)
static void pop(BuildContext context, [Object? result]) {
Navigator.of(context).pop(result);
}
// 弹出当前页面并返回数据
static void popWithResult(BuildContext context, Object? result) {
Navigator.of(context).pop(result);
}
// 弹出所有页面并跳转到指定页面
static Future<T?> pushAndRemoveUntil<T extends Object?>(
BuildContext context,
String routeName, {
Object? arguments,
}) {
return Navigator.of(context).pushNamedAndRemoveUntil(
routeName,
(route) => false,
arguments: arguments,
);
}
// 处理未注册的路由
static Route<dynamic> onUnknownRoute(RouteSettings settings) {
return MaterialPageRoute(
builder: (context) => const ErrorScreen(),
settings: settings,
);
}
}
✅ 2. 定义页面组件(示例)
// lib/screens/home_screen.dart
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Home')),
body: Center(
child: ElevatedButton(
onPressed: () {
Router.pushNamed(context, '/detail', arguments: 'Detail Page');
},
child: const Text('Go to Detail'),
),
),
);
}
}
// lib/screens/detail_screen.dart
import 'package:flutter/material.dart';
class DetailScreen extends StatelessWidget {
final String arguments;
const DetailScreen({Key? key, required this.arguments}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Detail: $arguments')),
body: Center(
child: ElevatedButton(
onPressed: () => Router.pop(context),
child: const Text('Back'),
),
),
);
}
}
// lib/screens/settings_screen.dart
import 'package:flutter/material.dart';
class SettingsScreen extends StatelessWidget {
const SettingsScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Settings')),
body: const Center(child: Text('Settings Page')),
);
}
}
// lib/screens/error_screen.dart
import 'package:flutter/material.dart';
class ErrorScreen extends StatelessWidget {
const ErrorScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('404')),
body: const Center(child: Text('Page Not Found')),
);
}
}
✅ 3. 在 main.dart
中注册路由
// lib/main.dart
import 'package:flutter/material.dart';
import 'router/router.dart';
import 'screens/home_screen.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Router Demo',
initialRoute: '/',
onGenerateRoute: Router.routeTable.isEmpty
? null
: (settings) => MaterialPageRoute(
builder: (context) => Router.routeTable[settings.name]!(context),
settings: settings,
),
onUnknownRoute: Router.onUnknownRoute,
home: const HomeScreen(),
);
}
}
✅ 4. 使用封装的跳转方法
// 示例:跳转到详情页并传递参数
Router.pushNamed(context, '/detail', arguments: 'Hello from Home');
// 示例:跳转并替换当前页面
Router.pushReplacementNamed(context, '/settings');
// 示例:弹出当前页面
Router.pop(context);
// 示例:弹出所有页面并跳转到首页
Router.pushAndRemoveUntil(context, '/');
✅ 5. 优势总结
优点 | 说明 |
---|---|
统一管理 | 所有页面跳转逻辑集中在 Router 类中,便于维护。 |
参数传递 | 支持带参数的跳转和返回数据处理。 |
错误处理 | 自动处理未注册的路由(404 页面)。 |
可扩展性强 | 可轻松添加新页面或修改现有路由规则。 |
通过这种方式,你可以将 Flutter 应用中的页面跳转逻辑统一管理,提升代码结构的清晰度和可维护性。如果你有更复杂的需求(如嵌套路由、动画跳转等),也可以在此基础上扩展。
✅ 6. 命名空间错误解决
这个错误是因为 Flutter 框架中的 Router
类(来自 package:flutter/src/widgets/router.dart
)与你自定义的 Router
类(来自 package:my_app/alearn_demo/router_demo/router.dart
)发生了 命名冲突。你需要通过 重命名导入 或 隐藏冲突类 的方式来解决这个问题。
✅ 解决方案一:使用 as
重命名导入
通过给其中一个库添加别名,区分冲突的 Router
类。
修改 main.dart
或其他使用 Router
的文件
// 1. 导入 Flutter 的 Material 库(默认会引入 Router 类)
import 'package:flutter/material.dart' as flutter;
// 2. 导入自定义的 Router 类(添加别名)
import 'package:my_app/alearn_demo/router_demo/router.dart' as my_router;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return flutter.MaterialApp(
title: 'Router Demo',
initialRoute: '/',
onGenerateRoute: (settings) => flutter.MaterialPageRoute(
builder: (context) => my_router.Router.routeTable[settings.name]!(context),
),
onUnknownRoute: my_router.Router.onUnknownRoute,
home: const my_router.HomeScreen(),
);
}
}
修改自定义的 Router.dart
文件
确保你的 Router
类使用的是自己的命名空间:
// lib/alearn_demo/router_demo/router.dart
import 'package:flutter/material.dart';
class Router {
// 你的路由表和跳转方法...
}
✅ 解决方案二:使用 hide
隐藏冲突类
如果只需要使用 Flutter 的 MaterialApp
等组件,但不需要框架的 Router
类,可以通过 hide
隐藏它。
修改导入语句
// 隐藏 Flutter 中的 Router 类
import 'package:flutter/material.dart' hide Router;
// 导入自定义的 Router 类
import 'package:my_app/alearn_demo/router_demo/router.dart';
✅ 补充说明
-
为什么会出现冲突?
- Flutter 的
MaterialApp
会隐式导入material.dart
,而material.dart
会引入Router
类(用于新路由系统)。如果你的代码中也定义了一个Router
类,就会发生冲突。
- Flutter 的
-
推荐做法
- 如果你使用的是 Flutter 2.5+ 的 新路由系统(基于
Router
类),则需要保留 Flutter 的Router
,并重命名你的自定义路由管理类(如MyRouter
)。 - 如果你使用的是传统的
Navigator
路由(基于pushNamed
),可以安全地隐藏 Flutter 的Router
类。
- 如果你使用的是 Flutter 2.5+ 的 新路由系统(基于
✅ 修改后的完整示例
main.dart
// 隐藏 Flutter 的 Router 类
import 'package:flutter/material.dart' hide Router;
// 导入自定义的 Router 类
import 'package:my_app/alearn_demo/router_demo/router.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Router Demo',
initialRoute: '/',
onGenerateRoute: (settings) => MaterialPageRoute(
builder: (context) => Router.routeTable[settings.name]!(context),
),
onUnknownRoute: Router.onUnknownRoute,
home: const HomeScreen(),
);
}
}
Router.dart
// lib/alearn_demo/router_demo/router.dart
import 'package:flutter/material.dart';
class Router {
static final Map<String, WidgetBuilder> routeTable = {
'/': (context) => const HomeScreen(),
'/detail': (context) => DetailScreen(),
};
static Future<T?> pushNamed<T extends Object?>(
BuildContext context,
String routeName,
) {
return Navigator.pushNamed<T>(context, routeName);
}
// 其他方法...
}
✅ 总结
问题 | 原因 | 解决方案 |
---|---|---|
Router 类冲突 | Flutter 框架和自定义代码中都定义了 Router 类 | 使用 as 重命名导入或 hide 隐藏冲突类 |
推荐做法 | 使用传统 Navigator 路由时 | 隐藏 Flutter 的 Router 类 |
新路由系统需求 | 使用 Flutter 的 Router 类 | 重命名自定义类(如 MyRouter ) |
通过以上方法,你可以轻松解决命名冲突问题,并保持代码的清晰性。