Appearance
Flutter 路由导航
什么是路由导航
路由导航是指在应用中不同页面之间的切换。在 Flutter 中,路由导航是通过 Navigator 组件实现的。
基本导航
1. 命名路由
命名路由是在应用初始化时定义的路由,可以通过名称进行导航。
配置路由:
dart
void main() {
runApp(
MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => HomePage(),
'/details': (context) => DetailsPage(),
'/settings': (context) => SettingsPage(),
},
),
);
}1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
导航到路由:
dart
// 导航到新页面
Navigator.pushNamed(context, '/details');
// 带参数导航
Navigator.pushNamed(
context,
'/details',
arguments: 'Hello from home',
);1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
获取路由参数:
dart
class DetailsPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final String message = ModalRoute.of(context)!.settings.arguments as String;
return Scaffold(
appBar: AppBar(title: Text('Details')),
body: Center(child: Text(message)),
);
}
}1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2. 匿名路由
匿名路由是通过 MaterialPageRoute 直接创建的路由。
导航到新页面:
dart
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailsPage(),
),
);
// 带参数
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailsPage(message: 'Hello from home'),
),
);1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
返回上一页:
dart
Navigator.pop(context);
// 返回并带结果
Navigator.pop(context, 'Result from details');1
2
3
4
2
3
4
接收返回结果:
dart
// 导航并等待结果
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => DetailsPage()),
);
// 使用结果
print('Result: $result');1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
路由替换
1. 替换当前路由
用新路由替换当前路由,这样用户就无法通过返回按钮回到当前页面。
dart
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => NewPage()),
);
// 命名路由
Navigator.pushReplacementNamed(context, '/new');1
2
3
4
5
6
7
2
3
4
5
6
7
2. 替换所有路由
替换整个路由栈,通常用于登录后跳转到主页面。
dart
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => MainPage()),
(route) => false, // 移除所有之前的路由
);
// 命名路由
Navigator.pushNamedAndRemoveUntil(
context,
'/main',
(route) => false,
);1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
路由动画
1. 自定义页面过渡动画
dart
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) => DetailsPage(),
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,
);
},
),
);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2. 预定义动画
Flutter 提供了一些预定义的页面过渡动画:
MaterialPageRoute- 标准的 iOS 和 Android 过渡动画CupertinoPageRoute- iOS 风格的过渡动画
dart
// iOS 风格动画
Navigator.push(
context,
CupertinoPageRoute(builder: (context) => DetailsPage()),
);1
2
3
4
5
2
3
4
5
路由管理库
1. auto_route
auto_route 是一个功能强大的路由管理库,支持代码生成。
安装:
bash
flutter pub add auto_route
flutter pub add --dev build_runner auto_route_generator1
2
2
配置:
dart
// 1. 定义路由
@MaterialAutoRouter(
replaceInRouteName: 'Page,Route',
routes: <AutoRoute>[
AutoRoute(page: HomePage, initial: true),
AutoRoute(page: DetailsPage),
AutoRoute(page: SettingsPage),
],
)
class $AppRouter extends RootStackRouter {}
// 2. 生成路由代码
// 运行命令: flutter pub run build_runner build
// 3. 使用路由
class MyApp extends StatelessWidget {
final _appRouter = AppRouter();
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routerDelegate: _appRouter.delegate(),
routeInformationParser: _appRouter.defaultRouteParser(),
);
}
}
// 4. 导航
context.router.push(DetailsRoute());1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2. go_router
go_router 是 Flutter 官方推荐的路由管理库,使用声明式 API。
安装:
bash
flutter pub add go_router1
配置:
dart
final goRouter = GoRouter(
initialLocation: '/',
routes: [
GoRoute(
path: '/',
builder: (context, state) => HomePage(),
),
GoRoute(
path: '/details/:id',
builder: (context, state) {
final id = state.params['id']!;
return DetailsPage(id: id);
},
),
GoRoute(
path: '/settings',
builder: (context, state) => SettingsPage(),
),
],
);
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routerConfig: goRouter,
);
}
}
// 导航
goRouter.push('/details/123');
// 带查询参数
goRouter.push('/details/123?name=flutter');1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
路由守卫
1. 实现路由守卫
路由守卫用于控制路由的访问权限,例如检查用户是否登录。
使用 go_router 实现:
dart
final goRouter = GoRouter(
initialLocation: '/',
routes: [
GoRoute(
path: '/',
builder: (context, state) => HomePage(),
),
GoRoute(
path: '/login',
builder: (context, state) => LoginPage(),
),
GoRoute(
path: '/profile',
builder: (context, state) => ProfilePage(),
redirect: (context, state) {
// 检查用户是否登录
if (!isLoggedIn) {
return '/login';
}
return null; // 允许访问
},
),
],
);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2. 全局路由守卫
dart
final goRouter = GoRouter(
initialLocation: '/',
redirect: (context, state) {
// 全局路由守卫逻辑
final isLoggedIn = checkIfLoggedIn();
final isLoginPage = state.location == '/login';
if (!isLoggedIn && !isLoginPage) {
return '/login';
}
if (isLoggedIn && isLoginPage) {
return '/';
}
return null;
},
routes: [
// 路由定义
],
);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
深度链接
1. 配置深度链接
Android 配置:
在 AndroidManifest.xml 中添加:
xml
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<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"
android:host="example.com"
android:pathPrefix="/details"
/>
</intent-filter>
</activity>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
iOS 配置:
在 Info.plist 中添加:
xml
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
<key>CFBundleURLName</key>
<string>com.example.myapp</string>
</dict>
</array>1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2. 处理深度链接
dart
final goRouter = GoRouter(
initialLocation: '/',
routes: [
GoRoute(
path: '/',
builder: (context, state) => HomePage(),
),
GoRoute(
path: '/details/:id',
builder: (context, state) {
final id = state.params['id']!;
return DetailsPage(id: id);
},
),
],
);
// 现在可以通过 myapp://example.com/details/123 打开应用并导航到详情页1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
导航最佳实践
- 使用命名路由:对于复杂应用,使用命名路由可以使代码更清晰
- 合理使用路由管理库:对于大型应用,考虑使用 auto_route 或 go_router
- 实现路由守卫:保护需要权限的页面
- 处理返回结果:正确处理页面间的返回结果
- 添加适当的过渡动画:提升用户体验
- 配置深度链接:支持从外部打开应用的特定页面
总结
Flutter 提供了强大的路由导航系统,支持多种导航方式和自定义动画。通过合理使用路由导航,可以创建流畅的用户体验。对于复杂应用,建议使用专门的路由管理库来简化路由管理。