深入解析 Flutter 路由与导航:从基础到项目实战
在 Flutter 中,路由与导航是构建多页面应用的核心功能。无论是简单的页面跳转,还是复杂的多级路由管理,掌握路由与导航的使用是开发高质量 Flutter 应用的关键。本篇博客将从基础到高级,详细介绍 Flutter 的路由与导航功能,并结合实际项目场景,探讨如何使用第三方路由库(如 go_router 和 auto_route)实现高效的路由管理。
1. 路由与导航的基础概念
1.1 什么是路由?
- 路由是页面的唯一标识符,用于管理页面的跳转和导航。
- 在 Flutter 中,路由可以是一个简单的字符串(命名路由)或一个复杂的对象(自定义路由)。
1.2 Navigator 的作用
Navigator是 Flutter 提供的内置导航管理器,用于管理页面的堆栈。- 页面跳转时,新的页面会被推入堆栈;返回时,页面会从堆栈中弹出。
2. Flutter 内置路由与导航
2.1 基本路由
Flutter 提供了 Navigator.push 和 Navigator.pop 方法,用于实现页面的跳转和返回。
示例代码
// 页面 A
class PageA extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("页面 A")),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => PageB()),
);
},
child: Text("跳转到页面 B"),
),
),
);
}
}
// 页面 B
class PageB extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("页面 B")),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text("返回页面 A"),
),
),
);
}
}
代码解析
Navigator.push:- 将页面 B 推入导航堆栈。
- 使用
MaterialPageRoute定义页面的路由。
Navigator.pop:- 从导航堆栈中弹出页面 B,返回页面 A。
2.2 命名路由
命名路由通过字符串标识页面,适合管理多页面应用。
示例代码
void main() {
runApp(MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => PageA(),
'/pageB': (context) => PageB(),
},
));
}
// 页面 A
class PageA extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("页面 A")),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/pageB');
},
child: Text("跳转到页面 B"),
),
),
);
}
}
// 页面 B
class PageB extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("页面 B")),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text("返回页面 A"),
),
),
);
}
}
代码解析
initialRoute:定义应用的初始路由。routes:定义路由表,映射路由名称到页面。
2.3 路由传参
在页面跳转时,可以通过路由传递参数。
示例代码
// 页面 A
class PageA extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("页面 A")),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PageB(data: "Hello from Page A"),
),
);
},
child: Text("跳转到页面 B"),
),
),
);
}
}
// 页面 B
class PageB extends StatelessWidget {
final String data;
PageB({required this.data});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("页面 B")),
body: Center(
child: Text(data),
),
);
}
}
3. 第三方路由库的使用
3.1 为什么使用第三方路由库?
- 内置路由的局限性:
- 路由表难以管理,尤其是多级嵌套路由。
- 缺乏路由拦截和守卫功能。
- 第三方路由库的优势:
- 提供更强大的路由管理功能。
- 支持嵌套路由、动态路由和路由守卫。
3.2 使用 go_router
go_router 是一个轻量级的路由库,支持嵌套路由和动态路由。
安装
dependencies:
go_router: ^6.0.0
示例代码
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final GoRouter _router = GoRouter(
initialLocation: '/',
routes: [
GoRoute(
path: '/',
builder: (context, state) => PageA(),
),
GoRoute(
path: '/pageB',
builder: (context, state) => PageB(data: state.queryParams['data'] ?? ''),
),
],
);
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routerConfig: _router,
);
}
}
// 页面 A
class PageA extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("页面 A")),
body: Center(
child: ElevatedButton(
onPressed: () {
context.go('/pageB?data=Hello%20from%20Page%20A');
},
child: Text("跳转到页面 B"),
),
),
);
}
}
// 页面 B
class PageB extends StatelessWidget {
final String data;
PageB({required this.data});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("页面 B")),
body: Center(
child: Text(data),
),
);
}
}
代码解析
GoRouter:定义路由表和初始路由。- 动态路由参数:通过
queryParams获取路由参数。 context.go:实现页面跳转。
3.3 使用 auto_route
auto_route 是一个功能强大的路由库,支持代码生成和路由守卫。
安装
dependencies:
auto_route: ^5.0.0
auto_route_generator: ^5.0.0
dev_dependencies:
build_runner: ^2.0.0
示例代码
-
定义路由表:
import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; @MaterialAutoRouter( routes: <AutoRoute>[ AutoRoute(page: PageA, initial: true), AutoRoute(page: PageB), ], ) class $AppRouter {} -
生成路由代码:
flutter pub run build_runner build -
使用路由:
final _appRouter = AppRouter(); @override Widget build(BuildContext context) { return MaterialApp.router( routerDelegate: _appRouter.delegate(), routeInformationParser: _appRouter.defaultRouteParser(), ); }
4. 项目实战:实现一个多页面电商应用
4.1 功能需求
- 首页:展示商品分类。
- 商品详情页:展示商品详情。
- 购物车页:展示已添加的商品。
4.2 路由设计
/:首页/product/:id:商品详情页/cart:购物车页
4.3 使用 go_router 实现路由
完整代码
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final GoRouter _router = GoRouter(
initialLocation: '/',
routes: [
GoRoute(
path: '/',
builder: (context, state) => HomePage(),
),
GoRoute(
path: '/product/:id',
builder: (context, state) {
final id = state.params['id']!;
return ProductPage(productId: id);
},
),
GoRoute(
path: '/cart',
builder: (context, state) => CartPage(),
),
],
);
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routerConfig: _router,
);
}
}
// 首页
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("首页")),
body: ListView(
children: [
ListTile(
title: Text("商品 1"),
onTap: () => context.go('/product/1'),
),
ListTile(
title: Text("商品 2"),
onTap: () => context.go('/product/2'),
),
],
),
);
}
}
// 商品详情页
class ProductPage extends StatelessWidget {
final String productId;
ProductPage({required this.productId});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("商品详情")),
body: Center(
child: Text("商品 ID: $productId"),
),
);
}
}
// 购物车页
class CartPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("购物车")),
body: Center(
child: Text("购物车为空"),
),
);
}
}
总结
-
基础路由:
- 使用
Navigator实现页面跳转和返回。 - 使用命名路由管理多页面应用。
- 使用
-
第三方路由库:
- 使用
go_router实现嵌套路由和动态路由。 - 使用
auto_route提供代码生成和路由守卫功能。
- 使用
-
项目实战:
- 通过路由设计和动态参数传递,构建一个多页面电商应用。