前言
咱们程序员最有B格的时候,无非是在小白面前敲着一行又一行的代码(记得换成黑色的背景,不要问为什么,一因为帅就完了),然后使屏幕浮现出炫酷的动画,这才是最有B格的时候,那普通人又看不懂咱的逻辑,对吧~
无论是App还是Web又或者是桌面程序,每一处都有页面间的跳转 ,毕竟一个应用程序都包含多个页面,咱不能一直往下滑吧哈哈
在 Flutter 中,这些元素被称为路由(Route),它们由导航器(Navigator) 控件管理。导航器管理着路由对象的堆栈并提供管理堆栈的方法,如 Navigator.push
和 Navigator.pop
,通过路由对象的进出栈来使用户从一个页面跳转到另一个页面。
详解图:
Navigator的职责是负责管理Route的,管理方式就是利用一个栈不停压入弹出,当然也可以直接替换其中某一个Route。而Route作为一个管理单元,主要负责创建对应的界面,响应Navigator压入路由和弹出路由。
Flutter定义路由的方式跟前端MVC框架是很相似的,你会看到有这种类似的:/home,/posts,/posts/:id等等,搞前端的同学应该想到熟悉。
本小节内容:
1.普通路由
2.Navigator
1).Navigator.push()
2).Navigator.pop()
3.路由表的管理
4.Navigator.pushNamed()
5.构造方法传值
6.路由传值
7.带数据返回
哎呀妈呀,这一节干货也太多了吧,这要个赞不过分吧,我不要下次一定!!
1.普通路由
Route:一个页面要想被路由统一管理,必须包装为一个Route
官方的说法很清晰:An abstraction for an entry managed by a Navigator.
但是Route是一个抽象类,所以它是不能实例化的.
2.Navigator
Navigator:是一个路由管理的组件,它提供了打开和退出路由页方法。Navigator通过一个栈来管理活动路由集合。通常当前屏幕显示的页面就是栈顶的路由。
官方解释:A widget that manages a set of child widgets with a stack discipline.
两个路由之间的跳转需要经历下面三个步骤
- 创建两个route
- Navigate到第二个route使用Navigator.push()
- 返回到第一个route使用Navigator.pop()
1).所以,让我们先来创建两个路由
class FirstRoute extends StatefulWidget {
@override
State<StatefulWidget> createState() => FirstState()
}
class FirstState extends State<FirstRoute> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: MaterialButton(
child: Text("点击跳转到第二个界面"),
onPressed: () {
///处理点击事件
},
),
),
);
}
}
class FirstRoute extends StatefulWidget {
@override
State<StatefulWidget> createState() => FirstState();
}
class FirstState extends State<FirstRoute> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
SizedBox(
height: 320,
),
Center(
child: MaterialButton(
child: Text("点击跳转到第一个界面"),
onPressed: () {
///处理点击事件
},
),
),
Center(
child: MaterialButton(
child: Text("点击返回到第一个界面"),
onPressed: () {
///处理点击事件
},
),
),
],
));
}
}
2).使用Navigator.push()来跳转页面
在FirstRoute组件中的onPressed方法中添加我们的Navigator
onPressed: () {
///处理点击事件
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => SecondRoute()));
},
注意:Navigator类中第一个参数为context的静态方法都对应一个Navigator的实例方法
Navigator.push(BuildContext context, Route route)
Navigator.of(context).push(Route route)
这两种写法是等价的
3).使用Navigator.pop()来返回上一个页面
我们使用Navigator.pop()来退出SecondRoute并回到FirstRoute,pop()方法回将当前路由从Route栈中移除
在返回按钮中写:
onPressed: () {
///处理返回点击事件
Navigator.pop(context);
},
当然我们也可以在跳转到第一个界面的里面写Navigator.push,不过不推荐这样的写法,因为这样的话没有吧页面从栈中移除。
3.路由表的管理
如果我们的项目中出现了多次跳转到同一个页面的情况,这种方式会造成大量代码的重复,路由表就很好的解决了这个问题。
咋这么多路由呢,感觉在上路由交换的课程哈哈
定义路由表
在MaterialApp的构造方法中添加两个额外的属性:initialRoute和routes
return MaterialApp(
title: 'Flutter Route',
theme: ThemeData(
primarySwatch: Colors.blue,
),
// 定义APP启动时第一个显示的页面
initialRoute: '/',
routes: {
// 当navigating到‘/’ route时,FirstRoute widget
'/': (context) => FirstRoute(),
// 当navigating 到"/second" route, SecondRoute widget.
'/second': (context) => SecondRoute(),
},
///指定了initialRoute,home就是多余的了
//home: FirstRoute(),
);
路由表是给每个Route定义了一个名称,这样我们就可以根据这个名称来进行跳转了。
4.Navigator.pushNamed()
通过这个方法跳转时,Flutter会去定义的routes中转到名称所对应的route,并进行跳转。
onPressed: () {
///处理点击事件
///普通跳转
// Navigator.of(context)
// .push(MaterialPageRoute(builder: (context) => SecondRoute()));
///通过路由表跳转
Navigator.pushNamed(context, "/second");
},
5.构造方法传值
使用于普通跳转,在自定义封装或者写插件时经常会用到。
我们可以在SecondRoute中定义几个参数:
class SecondRoute extends StatefulWidget {
final int age;
final String name;
const SecondRoute({Key key, this.age, this.name}) : super(key: key);
@override
State<StatefulWidget> createState() => SecondState();
}
通过构造方法获取参数
这下我们就可以在跳转时传参啦:
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => SecondRoute(age: 20,name: "阿T",)));
使用传入的参数:
Text(
"我的年龄:" + widget.age.toString() + " 我的姓名 " + widget.name)
6.路由传值
让我们先看看Navigator.pushNamed()的源码:
@optionalTypeArgs
static Future<T> pushNamed<T extends Object>(
BuildContext context,
//路由路径
String routeName, {
//携带的参数
Object arguments,
}) {
return Navigator.of(context).pushNamed<T>(routeName, arguments: arguments);
}
arguments是跳转携带的参数,它是一个Object,意味着可以传递任意类型的参数。
1)多个数据时准备一个bean
class ScreenArguments {
final String title;
final String message;
ScreenArguments(this.title, this.message);
}
2)跳转界面
Navigator.pushNamed(
context,
ExtractArgumentsScreen.routeName,
arguments: ScreenArguments(
'title',
'message',
)
3)获取参数
final ScreenArguments args = ModalRoute.of(context).settings.arguments;
4)使用参数
Text(args.title),
Text(args.message),
7.带数据返回
Navigator.pop(context, '返回的数据');
由于源码中 pop的方法是Object,这里可以传递任意类型参数返回
@optionalTypeArgs
static void pop<T extends Object>(BuildContext context, [ T result ]) {
Navigator.of(context).pop<T>(result);
}
基础路由就这样简单的实现啦
欢迎留言纠正 ~ 不妨给个点赞哈哈