一、介绍
在安卓里,界面(Activity)的跳转是通过startActivity来完成。而在Flutter里,把界面称作为一个个Route,他们的跳转是通过一个叫做路由管理(Navigator)的工具,负责页面之前的跳转,包括参数的传递接受和返回。Navigator的方法总的来说就两个,push(进栈),pop(出栈),跟Activity一样也会生成一个存放页面的栈。
二、页面跳转
首先,我们创建一个新的页面,如下
class TwoPageRoute extends StatelessWidget {
const TwoPageRoute({Key? key,}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("第二个页面"),
),
);
}
}
2.1 普通跳转
可以看到,在界面添加了跳转到TwoPageRoute页面的按钮。
TextButton(
child: const Text("通过实例跳转"),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return const TwoPageRoute();
}));
},
)
**提示1:**关于MaterialPageRoute可以理解为对路由界面的一个封装,继承于PageRoute,定义了页面之前跳转的动画,可以针对不同平台,实现与平台页面切换动画风格一致的路由切换动画。
**提示2:**在Flutter中,如果代码是固定的,也就是写死的,编译器会建议加上const。如果你是通过值传递的,那自然就不能加const了。
2.2 参数跳转
界面的跳转中,经常都需要传递参数。下面我们传递一个String参数和一个Bean类
UserBean类
class UserBean{
String name;
int age;
UserBean(this.name, this.age);
}
修改TwoPageRoute页面,增加两个参数,text和userBean。可以看到,在他们前面有个required关键字,意思是必传,这在很多Widget都会见到。
class TwoPageRoute extends StatelessWidget {
const TwoPageRoute({Key? key,
required this.text, // 接收一个text参数
required this.userBean //接收一个userBean类
}) : super(key: key);
final String text;
final UserBean userBean;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("第二个页面"),
),
body: Center(
child: Column(
children: [
Text("接受text值:$text"),
Text("接受userBean值:${userBean.toString()}"),
],
),
),
);
}
}
修改TextButton中的传参
TextButton(
child: const Text("通过实例跳转"),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return TwoPageRoute(
text: "我是第一个页面", userBean: UserBean("小小虫", 18));
}));
},
)
2.2 接收参数返回
在Flutter,接受页面的返回参数,相比安卓会比较方便,如下:
TextButton(
child: const Text("通过实例跳转"),
onPressed: () async {
var result = await Navigator.push(context,
MaterialPageRoute(builder: (context) {
return TwoPageRoute(
text: "我是第一个页面", userBean: UserBean("小小虫", 18));
}));
print("路由返回值: $result");
},
)
修改TwoPageRoute页面,添加一个按钮返回参数
TextButton(
onPressed: () {
Navigator.pop(context, "我是返回值");
},
child: const Text("关闭页面并返回值")
)
**注意1:**关键词async和await,不然不会等待页面结束接受返回值。关键词async和await,不然不会等待页面结束接受返回值。
三、路由命名跳转
? 在Flutter中,页面的跳转除了通过上面的方法外,还有一种通过路由命名跳转,类似于安卓的隐式跳转,安卓的如下:
<action android:name="com.example.SplashActivity" />
而在Flutter中,需要在MyApp中添加routes参数,如下:
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
//注册路由表
routes: {
"custom_page": (context) => const CustomRoute(),
},
);
}
}
增加一个TextButton,可以看到,路由命名的跳转需要通过pushNamed方法,支持arguments传参,是不是很熟悉的样子👀
TextButton(
child: const Text("通过自定义命名路由跳转"),
onPressed: () async {
var result = await Navigator.pushNamed(context, "custom_page",
arguments: "hello,我是通过自定义命名路由跳转");
print("通过自定义命名路由跳转路由返回值: $result");
},
)
然后修改CustomRoute页面,在build中获取参数,如下:
@override
Widget build(BuildContext context) {
//获取路由参数
var args=ModalRoute.of(context)?.settings.arguments;
}
如果你想两种结合在一起,把TwoPageRoute也加到routes中,还是最好不要吧🤣
修改routes,增加two_page_route
routes: {
"two_page_route": (context) {
dynamic obj = ModalRoute.of(context)!.settings.arguments;
return TwoPageRoute(text: obj["text"],userBean:obj["user"] ,);
},
}
修改参数,flutter的arguments的类型真的是很百变👍,感觉出问题的几率也会很高。
TextButton(
child: const Text("通过自定义命名路由跳转"),
onPressed: () async {
var result = await Navigator.pushNamed(context, "two_page_route",
arguments: <String, Object>{
'text': '我是第一个页面',
'user': UserBean("小小虫", 181),
});
print("通过自定义命名路由跳转路由返回值: $result");
},
)
四、路由钩子
? 所谓的路由钩子,其实就是一些路由相关的监听方法(监听就监听,还钩子)。
例如:
- onGenerateRoute:通过命名路由打开是会被调用。注意!重点!重点!是对应的name没有在routes中有映射关系,那么就会执行onGenerateRoute钩子函数,也就是没有在routes中注册路由。
- onUnknowRoute:在打开一个不存在的命名路由时会被调用
- navigatorObservers:监听所有路由跳转动作
举几个栗子
onGenerateRoute使用,在MaterialApp中添加onGenerateRoute,如下:
@override
Widget build(BuildContext context) {
return MaterialApp(
onGenerateRoute: (RouteSettings settings) {
var routeName = settings.name;
var isLogin = true;
if(routeName == "two_page_route" && isLogin){
return MaterialPageRoute(builder: (context) {
return TwoPageRoute(text: "我是第一个页面", userBean: UserBean("小小虫", 18));
});
}else{
//登录逻辑。。。
}
},
);
}
}
**注意:**记得先把two_page_route从routes去掉!
navigatorObservers使用,在MaterialApp中添加navigatorObservers,如下:
@override
Widget build(BuildContext context) {
return MaterialApp(
//监听所有路由跳转动作,
navigatorObservers: [
MyNavigator()
],
);
}
新建一个MyNavigator类,如下:
import 'package:flutter/widgets.dart';
///导航栈的变化监听
class MyNavigator extends NavigatorObserver{
@override
void didPush(Route route, Route? previousRoute) {
super.didPush(route, previousRoute);
//监听每个路由进栈
}
@override
void didPop(Route route, Route? previousRoute) {
super.didPop(route, previousRoute);
//监听每个路由出栈
}
}
|