主题
路由管理
一、静态路由
使用 pushNamed 跳转
1. 新建一个页面 search.dart
dart
import 'package:flutter/material.dart';
class Search extends StatelessWidget {
const Search({super.key});
@override
Widget build(BuildContext context) {
var arguments = ModalRoute.of(context)?.settings.arguments;
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(arguments as String),
),
body: ElevatedButton(
onPressed: () {
Navigator.pop(context, 'pop路由返回值');
},
child: const Text("返回"))));
}
}2. 修改 main.dart
dart
import 'package:flutter/material.dart';
import 'search.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
routes: {
'/Search': (context) => const Search(),
},
home: Scaffold(
appBar: AppBar(
title: const Text('Flutter Demo'),
),
body: const Home(),
),
);
}
}
class Home extends StatelessWidget {
const Home({super.key});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () async {
var result = await Navigator.pushNamed(context, '/Search',
arguments: '我是命名路由参数');
//输出pop跳转返回结果
print("路由返回值: $result");
},
child: const Text("点击转跳"));
}
}不能直接在 body 属性上注册路由进行跳转
二、动态路由
动态路由无需在 MaterialApp 内的 routes 中注册即可直接使用
两种跳转方法:push,pop
1. 传参
dart
ElevatedButton(
onPressed: () async {
var result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const Search(
title: '路由传值',
)));
//输出pop跳转返回结果
print("路由返回值: $result");
},
child: const Text("点击转跳"))2. 接参
dart
import 'package:flutter/material.dart';
class Search extends StatelessWidget {
final String title;
const Search({super.key, required this.title});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: ElevatedButton(
onPressed: () {
Navigator.of(context).pop('pop路由返回值');
},
child: const Text("返回"))));
}
}有两种方式可以返回到上一页;第一种方式是直接点击导航栏返回箭头,第二种方式是点击页面中的「返回」按钮。这两种返回方式的区别是前者不会返回数据给上一个路由,而后者会
三、路由生成钩子(onGenerateRoute)
通过 onGenerateRoute 控制页面权限
原理:onGenerateRoute 在打开命名路由时可能会被调用,之所以说可能,是因为当调用 Navigator.pushNamed(...) 打开命名路由时,如果指定的路由名在路由表中已注册,则会调用路由表中的 builder 函数来生成路由组件;如果路由表中没有注册,才会调用 onGenerateRoute 来生成路由
dart
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
onGenerateRoute: (RouteSettings settings) {
print('dayin$settings');
//可以控制生成路由,做鉴权处理
final Route route = MaterialPageRoute(
builder: (context) => const DetailScreen(id: '2'));
return route;
},
home: const Login());
}
}
class Login extends StatelessWidget {
const Login({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: TextButton(
child: const Text('View Details'),
onPressed: () {
Navigator.pushNamed(
context,
'/home',
);
},
),
),
);
}
}
class DetailScreen extends StatelessWidget {
final String id;
const DetailScreen({
super.key,
required this.id,
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Viewing details for item $id'),
TextButton(
child: const Text('Pop!'),
onPressed: () {
Navigator.pop(context);
},
),
],
),
),
);
}
}四、路由懒加载
通过 deferred as 关键字将一个普通页面变成 deferred-components,然后在路由打开时通过 libraryFuture 加载后渲染页面
dart
//使用deferred as关键字
import 'search.dart' deferred as controller_demo_page;
//定义一个包裹组件
class ContainerAsyncRouterPage extends StatelessWidget {
final Future libraryFuture;
final WidgetBuilder child;
ContainerAsyncRouterPage(this.libraryFuture, this.child);
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: libraryFuture,
builder: (c, s) {
if (s.connectionState == ConnectionState.done) {
if (s.hasError) {
return Scaffold(
appBar: AppBar(),
body: Container(
alignment: Alignment.center,
child: Text(
'Error: ${s.error}',
style: TextStyle(color: Colors.red),
),
),
);
}
return child.call(context);
}
return Scaffold(
appBar: AppBar(),
body: Container(
alignment: Alignment.center,
child: CircularProgressIndicator(),
),
);
});
}
}
//修改router
Map<String, WidgetBuilder> router = {
'search': (context) {
return ContainerAsyncRouterPage(controller_demo_page.loadLibrary(),
(context) {
return controller_demo_page.DetailScreen();
});
}
};运行 flutter build web,在 build/web 中查看文件