Flutter入门-路由
路由
Flutter使用路由来定义页面之间的跳转,类似Vue。Flutter使用Navigator组件来管理路由导航。
方法:
- Navigator.push,跳转
- Navigator.pop, 返回上一级,如果是对话框,会关闭对话框。
普通路由
使用场景:在一些小型项目中推荐使用。
核心代码
跳转
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => const SearchPage(),
));
//传值
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => FormPage(title: "我是传递过来的值"),
));
返回或关闭
Navigator.of(context).pop();
演示案例
1、主页面
class HomePage extends StatefulWidget {
const HomePage({super.key});
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Widget build(BuildContext context) {
return Column(
children: [
//按钮1,使用漂浮按钮,设置点击事件,点击的时候,push到另一个页面
ElevatedButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => const SearchPage(),
));
},
child: const Text('跳转到搜索页面')),
//按钮2,跳转传值,通过构造函数传值。
ElevatedButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => FormPage(title: "我是传递过来的值"),
));
},
child: const Text('跳转到表单页面并传值')),
],
);
}
}
2、SearchPage,不传值
使用Scaffold,跳转过来的页面都会自带返回箭头,点击就会执行pop。
class SearchPage extends StatelessWidget {
const SearchPage({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("我是搜索页面"),
),
body: const Text("搜索页面内容区域"),
);
}
}
3、FormPage,传值
使用Scaffold,跳转过来的页面都会自带返回箭头,点击就会执行pop
class FormPage extends StatelessWidget {
String title;
//设置默认值,没有传值将会使用默认值
FormPage({super.key, this.title = "表单"});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: ListView(
children: const [
ListTile(
title: Text("item标题"),
subtitle: Text("item描述"),
),
],
),
//也可以手动添加返回按钮,使用floatingActionButton
floatingActionButton: FloatingActionButton(
child: const Text('返回'),
onPressed: () {
Navigator.of(context).pop();
},
),
);
}
}
命名路由
如果是大型项目,路由比较多,我们希望可以统一管理所有的路由,就可以使用命名路由。
基本使用
1、定义命名路由
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
theme: ThemeData(primarySwatch: Colors.blue),
home: Tabs(),
routes: {
'/form': (context) => FormPage(),
'/search': (context) => SearchPage(),
},
);
}
}
路由的名称,我们也可以根据模块进行区分
/user/login
/user_login
user_login
怎样都可以。
2、页面跳转
直接通过 Navigator.pushNamed()
进行页面跳转。
return Column(
children: [
ElevatedButton(
onPressed: () {
//Navigator.of(context).push(MaterialPageRoute(builder: (context) => SearchPage()));
Navigator.pushNamed(context, '/search');
},
child: Text('跳转到搜索页面')),
ElevatedButton(
onPressed: () {
// Navigator.of(context).push(MaterialPageRoute(builder: (context) {
// //return FormPage(title: "我是传递过来的值");
// return FormPage();
// }));
Navigator.pushNamed(context, '/form');
},
child: Text('跳转到表单页面并传值')),
],
命名路由传值
1、定义路由,改造后
class MyApp extends StatelessWidget {
//1、抽取路由定义
final routes = {
'/search': (context) => SearchPage(),
'/form': (context, {arguments}) => FormPage(arguments: arguments),
};
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
theme: ThemeData(primarySwatch: Colors.blue),
home: Tabs(),
//2、路由监听,类似拦截器的效果,固定写法,固定代码
onGenerateRoute: (RouteSettings settings) {
//统一处理,进行了非空检查,也就是末尾添加感叹号
final String name = settings.name!;
final Function pageContentBuilder = this.routes[name]!;
if (pageContentBuilder != null) {
//如果有值就传值
if (settings.arguments != null) {
final Route route = MaterialPageRoute(
builder: (context) => pageContentBuilder(context,
arguments: settings.arguments));
return route;
} else {
//没有值直接跳转
final Route route = MaterialPageRoute(
builder: (context) => pageContentBuilder(context));
return route;
}
}
});
}
}
2、传递数据
return Column(
children: [
ElevatedButton(
onPressed: () {
//命名路由,不传值
Navigator.pushNamed(context, '/search');
},
child: Text('跳转到搜索页面')),
ElevatedButton(
onPressed: () {
//命名路由,不传值
//Navigator.pushNamed(context, '/form');
//命名路由,传值写法
Navigator.pushNamed(context, '/form', arguments: {
"title": "表单",
"name": "章三",
"desc": "我是描述内容",
});
},
child: Text('跳转到表单页面并传值')),
],
);
3、接收数据
class FormPage extends StatelessWidget {
//接收传递的参数
final arguments;
FormPage({this.arguments});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
//取出传递过来的数据
title: Text(arguments != null ? arguments['title'] : "default"),
),
body: ListView(
children: [
//取出传递过来的数据
ListTile(
title: Text(arguments != null ? arguments['name'] : "default"),
subtitle: Text(arguments != null ? arguments['desc'] : 'default'),
),
],
),
//手动添加返回按钮
floatingActionButton: FloatingActionButton(
child: Text('返回'),
onPressed: () {
Navigator.of(context).pop();
},
),
);
}
}
路由替换
不使用路由替换
ElevatedButton(
onPressed: () {
//这种方式跳转,下一页返回的时候直接返回到这一页
Navigator.pushNamed(context, '/register2');
},
child: const Text("下一步")),
使用路由替换
ElevatedButton(
onPressed: () {
//这种方式跳转,下一页返回返回到当前页的上一页。
Navigator.pushReplacementNamed(context, '/register2');
},
child: const Text("下一步")),
区别:
- 不使用路由替换,跳转到下一页之后,点击返回按钮,返回到当前页。
- 使用路由替换,跳转到下一页之后,点击返回按钮,返回到当前页的上一页。
返回根路径
假设注册分好几步,注册成功后,直接跳转到首页。通过Navigator.pushAndRemoveUntil可以直接跳转到指定的路由,并清空route
ElevatedButton(
onPressed: () {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => const Tabs(index: 2)),
(route) => route == null,
);
},
child: const Text("完成注册")),
抽取路由文件
//配置路由
final routes = {
'/': (context) => const Tabs(),
'/search': (context) => const SearchPage(),
'/form': (context, {arguments}) => FormPage(arguments: arguments),
'/product': (context) => const ProductPage(),
'/productInfo': (context, {arguments}) => ProductInfoPage(arguments: arguments),
'/login': (context) => const LoginPage(),
'/register1': (context) => const RegisterFirstPage(),
'/register2': (context) => const RegisterSecondPage(),
'/register3': (context) => const RegisterThirdPage(),
'/userCenter': (context) => const UserCenterPage(),
};
/*
* 这个方法是固定写法,功能就像是一个拦截器。
*/
var onGenerateRoute = (RouteSettings settings) {
//统一处理,进行了非空检查,也就是末尾添加感叹号
final String name = settings.name!;
debugPrint("访问的路由地址名称=$name");
final Function pageContentBuilder = routes[name]!;
if (settings.arguments != null) {
final Route route = MaterialPageRoute(builder: (context) => pageContentBuilder(context, arguments: settings.arguments));
return route;
} else {
//没有值直接跳转
final Route route = MaterialPageRoute(builder: (context) => pageContentBuilder(context));
return route;
}
};