今天学习下Flutter
的界面跳转,也就是路由的运用,首先我们需要创建两个界面LoginPage
、MenuPage
,然后把登录界面设为主界面,菜单界面设置为二级界面,我们有登录界面跳转到菜单界面:
// 登录界面
class LoginPage extends StatelessWidget {
const LoginPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("登录"),
),
body: TextButton(
onPressed: () {
// Navigator 路由
// 跳转代码
},
child: const Text("登录"),
),
);
}
}
// 二级界面
class MenuPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
dynamic arguments = ModalRoute.of(context)?.settings.arguments;
print(arguments);
return Scaffold(
appBar: AppBar(
title: Text("menu"),
),
);
}
}
我们把登录界面设置为主界面:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
debugShowCheckedModeBanner: false,
home: LoginPage(), // 设置主界面
);
}
}
下面介绍几种路由跳转:
一、 路由的普通跳转
我们使用Navigator
进行界面的跳转,我们在LoginPage
的点击事件中写跳转代码,如下:
// Navigator 路由
// 跳转代码
Navigator.of(context).push(MaterialPageRoute(
builder: (context) {
return const MenuPage();
},
// settings 会改一些路由的名称、参数 或者设置它跳转以后是不是新的主界面(就是有没有返回按钮)
settings: const RouteSettings(
name: "你好",
arguments: "",
),
// 跳转以后之前的路由是否要释放 false - 释放 ,true - 不释放
maintainState: false,
// 跳转之后是否是全屏的 flase(push跳转) 和 true(模态跳转) 转场动画不一样
fullscreenDialog: true,
));
跳转的时候我们需要用MaterialPageRoute
进行包装,,MaterialPageRoute
中有几个参数需要了解绍几个常用的:
builder
: 这里面返回的就是需要跳转到的界面settings
: 这里可以设置路由的名称、参数 或者设置它跳转以后是不是新的主界面(就是有没有返回按钮)maintainState
: 设置跳转以后之前的路由是否要释放 false - 释放 ,true - 不释放fullscreenDialog
: 跳转之后是否是全屏的 flase(push跳转) 和 true(模态跳转) 转场动画不一样
二、路由传值
- 组件传值
例如:我们需要传一个名字给二级的菜单界面,那我们首先在MenuPage
里写一个接收的对象:
// 接收的对象
final String title;
const MenuPage({Key? key, required this.title}) : super(key: key);
然后我们可以在标题赋值的时候使用title
:
appBar: AppBar(
title: Text(title),
),
传值的时候,我们只需要在初始化MenuPage
的时候把title
赋值就行了:
Navigator.of(context).push(MaterialPageRoute(
builder: (context) {
return const MenuPage(
title: "Menu",
);
},
));
这样就会在跳转的时候把Menu
这值传到MenuPage
界面。
- 参数传值
组件传值局限性比较大,这是我们也可以用MaterialPageRoute
中的settings
进行传值:
Navigator.of(context)
.push(MaterialPageRoute(
builder: (context) {
// 组件传值
return MenuPage();
},
settings: const RouteSettings(
name: "menu",
// 路由传值
arguments: "name", //也可以传对象
),
));
sttings
使用的时候我们需要用RouteSettings
包装,这个里面有name
、arguments
两参数:
name
:路由的名称(单独界面使用时候,可以为空,这个参数主要是为了区分不同的路由,后面封装路由的时候比较重要)
arguments
:需要传的参数,这个是泛型的,可以传任意类型的数据,包括对象。
当然在MenuPage
界面创建一个接收器,要不没法接收数据,我们使用ModalRoute
去接收:
Widget build(BuildContext context) {
// 接收参数
dynamic arguments = ModalRoute.of(context)?.settings.arguments;
print(arguments);
return Scaffold(
appBar: AppBar(
title: Text(arguments),
),
);
}
三、路由的返回值(反向传值)
我们有的时候,需要从二级界面回传一些值到一级界面,这时候就需要用到反向传值了,我这里介绍两种传值的方法:
- 1、使用
then
进行返回值的读取,也就是在Navigator
跳转方法后面添加then
方法:
Navigator.of(context)
.push(MaterialPageRoute(
builder: (context) {
// 组件传值
return MenuPage();
},
settings: const RouteSettings(
name: "menu",
// 路由传值
arguments: "name", //也可以传对象
),
)).then((value) =>
// 打印返回值
print(value)
);
我们在MenuPage
界面添加一个返回按钮,点击的时候,把参数传回主界面,pop
返回我们需要用到Navigator
中的pop
方法,返回的参数就可以在pop
里面添加:
body: TextButton(
onPressed: () {
// Navigator.of(context).pop("返回值");
// 返回对象
Navigator.of(context).pop({
"返回值"
// 也可以是个对象
// "name": "返回值",
});
},
child: const Text("返回"),
),
注
: 返回的不止是字符串
,也可以是个对象
,这是个泛型
- 2、 异步读取
我们也可以在跳转的时候,填个一个异步操作,我们可以对Navigator
添加一个接收对象result
,然后使用await
进行等待读取,await
修饰后,只有在有返回值得时候,才会进行下一步操作。
// 添加返回值
body: TextButton(
// 异步返回
onPressed: () async {
// await 等待,一直等到有返回值返回的时候才会走下一步 print(result);
var result = await Navigator.of(context).push(MaterialPageRoute(
builder: (context) {
return MenuPage();
},
// 打印返回值
print(result);
},
child: const Text("登录"),
),
四、路由的封装(系统的)
上面介绍的方法时在每个控制器去写路由的创建,这样比较麻烦,也不好去维护和扩展,我们可以吧路由的创建全部写在main.dart
里面,MaterialApp
这里面有个routes
参数,我们可以在这里面去添加各个控制器:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
debugShowCheckedModeBanner: false,
routes: {
"/": (context) => const LoginPage(),
"menu": (context) => MenuPage(),
},
// 指定界面为主界面
// initialRoute: "menu",
// home: LoginPage(),
);
}
}
- 使用
routes
的时候就不需要用home
去指定主界面了。routes
结构是: “路由名称” : => 初始化的控制器/
: 如果使用斜杠为路由的名字,系统就会默认此路由是主界面- 当然我们也可以使用
initialRoute
去指定一个路由为主界面
,只需要把路由的名字赋值给它就行。
我们在MyApp
里面设置玩路由之后,我们在各个控制器中使用路由的时候,只需要根据路由的名字
就能跳转了:
Navigator.of(context)
.pushNamed("menu", arguments: "menu123")
.then((value) => print(value));
使用的时候我们需要使用
pushNamed
方法根据路由的名字
去跳转,arguments
还是代表的需要传的参数。
这就是Flutter 路由
的初步学习,至于路由更便捷的操作和路由的高级用法,后续会慢慢的研究。