一、介绍:
路由在移动开发中通常指页面,路由管理就指的是管理页面之间的跳转,在flutter中,是通过一个栈的结构来对路由进行维护管理。路由管理也就是说在代码层面其实是对这个栈结构进行管理,其中路由入栈操作就相当于打开一个新的页面,放入这个栈结构中,路由出栈操作对应的是页面关闭操作,但是当一个APP中使用到页面很多时,如何更加有效合理的去管理各个页面之间的关系和跳转逻辑将变得极为重要。
**路由:**在flutter中,一个路由中维护了与之相关的路由状态,路由页,以及该路由对应的标签数据以及指针位置等内容。
**路由栈:**在我们的flutter项目中,页面的路由是通过一个栈结构进行管理并维护的,而栈的特点就是只能从栈顶位置进行插入内容和取出内容,当我们打开一个新的页面时,其实就是向这个栈结构中从顶部放入一个新的路由,随着打开的路由页逐渐变多,最先插入的路由将会逐渐被压入栈的底部,当我们从某个页面返回到上一页的时候,也是从栈顶位置pop出路由。
每一个存放在栈中的路由都存在2个指针,一个指向下一个路由next(在栈内位于当前路由之上的路由),一个指向上一个路由(在栈内位于当前路由之下的路由),通过栈的方式存储路由,通过链的方式维护路由之间的关系。
1、在flutter 中我们通过Navigator来完成对路由的操作
例:
//打开一个新的页面
Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return SecondPage();
}));
//返回上一个页面
Navigator.pop(context);
2、在flutter中除了最简单基本的打开新的页面与返回上一页之外还提供了其他方法来完成更加复杂的操作
pushReplacement:替换当前页面,并且当新页面动画执行完成之后dispose前一个页面
例:
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (BuildContext context) {
return ThirdPage();
},),result: 'second page');
newRoute:要打开的新路由页
Result:第三个可选参数result表示的是这个页面的返回结果,如果设置的话,会返回给被替换的这个页面的前一个页面。
pushAndRemoveUntil:跳转到指定页面,并按顺序(从栈顶到栈底)移出之前的所有页面,直到predicate(指定页面)返回true
例:
Navigator.pushAndRemoveUntil(context, MaterialPageRoute(
builder: (BuildContext context) {
return ThirdPage();
},
), (router) {
// flutter中root页settings.name默认为"/"
return router.settings.name == "/";
});
Context:上下文对象
newRoute:新路由页
Predicate:移除Predicate之上的的所有页面
例如从Page2调用跳转pushAndRemoveUntil到Page3,同时指定predicate的条件为route.settings.name == “/”,那么跳转到Page3后Page2将被移除,因为第一个页面的默认RouteSetting的name属性值为"/"。
如果predicate的条件为route.settings.name != “/”,那么任何一个页面都不会被移除,因为判断第一个前页面Page2的时候predicate已经返回true。
popUntil:按顺序从栈内移除最顶上的页面,直到predicate返回true
例:
Navigator.popUntil(context, (router) {
return router.settings.name == '/';
});
Context:上下文对象
Predicate:移除Predicate之上的的所有页面
3、数据的传递
将数据传递给下一个页面
非命名路由直接定义变量,直接使用路由的构造函数传参即可。
//在新页面的构造方法中接收上一个页面传递过来的数据
class SecondPage extends StatefulWidget {
var firstPageMsg;
SecondPage({this.firstPageMsg='星期天'});
@override
_SecondPageState createState() => _SecondPageState();
}
//在push方法中的PageRoute将需要传递的数据直接通过page的构造方法传入即可,理解不困难。
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) {
return SecondPage(firstPageMsg: '星期一',);
},
settings: RouteSettings(name: 'firstPage')))
.then((value) {
print('接收返回数据:$value');
});
2.将数据返回给上一页
使用pop方法,通过他的result将数据进行返回。
Navigator.pop(context, 'second page message');
@optionalTypeArgs
static void pop<T extends Object>(BuildContext context, [ T result ]) {
Navigator.of(context).pop<T>(result);
}
push方法会返回一个future,
@optionalTypeArgs
static Future<T> push<T extends Object>(BuildContext context, Route<T> route) {
return Navigator.of(context).push(route);
}
所以只需要通过then关键字就可以接收到返回的数据
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) {
return SecondPage(
firstPageMsg: '星期一',
);
},
settings: RouteSettings(name: 'firstPage')))
.then((value) {
print('接收返回数据:$value');
});
4、命名路由
适用于应用中页面比较多的情况,减少代码重复,方便统一进行管理。
使用命名路由:
1.提供一个路由集放入MaterialApp下的routes属性
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
routes: {
'FirstPage': (context) => FirstPage(),
'SecondPage': (context) => SecondPage(),
'ThirdPage': (context) => ThirdPage(),
},
//可以在onUnknownRoute中设置一个路由跳转错误页面
onUnknownRoute: (RouteSettings setting