概述
Flutter中,路由(Router)即页面的封装,一个路由内部包含了一个页面。创建路由:
MaterialPageRoute route = MaterialPageRoute(
builder: (BuildContext context) => MyPage(),
);
类似于在Android原生中以任务栈来管理Activity,在Flutter中以路由栈来管理路由。跳转到一个新页面,就是将其对应的路由加入到栈顶;退出一个页面,就是将其对应的路由出栈。
路由函数简介
push、pushNamed
将一个路由加入到栈顶,即跳转到一个新页面。
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => Page2()));
Navigator.pushNamed(context, routerName);
pushReplacement、pushReplacementNamed
将一个路由加入到栈顶,并将当前路由出栈(pop)。(也就是以一个新页面替换当前页面。在新页面的入场动画结束时,才会调用当前页面的dispose方法。)
pushAndRemoveUntil、pushNamedAndRemoveUntil
将一个路由加入到栈顶,并将其下方的路由逐一移除(remove),直到predicate函数返回了true。
//调用方式
Navigator.pushAndRemoveUntil(context, newRoute, predicate);
Navigator.pushNamedAndRemoveUntil(context, newRouteName, predicate);
//下面代码将名为Page6的路由加入到栈顶,并将其下方的路由逐一出栈,直到遇到名为MyHomePage的路由:
Navigator.pushNamedAndRemoveUntil(context, "Page6", ModalRoute.withName('MyHomePage'));
//下面代码将名为Page6的路由加入到栈顶,并将其下方的路由全部出栈,即,使Page6成为路由栈中唯一的路由:
Navigator.pushNamedAndRemoveUntil(context, "Page6", (route){return false;});
需要注意的是,被移除(remove)的路由将永远不会变成completed状态,也就是说将它入栈的push、pushNamed的返回值future将永远不会被complete。
pop
将栈顶的路由出栈。
被出栈的路由会变成completed状态。也就是说将其入栈的push、pushNamed的返回值future也会变成completed状态。
风险:如果路由栈中只有唯一的路由,那么将此路由出栈后,app并不会像Android原生那样退出,而是会展示一个黑屏界面。(因此在Flutter中,为了避免黑屏,在调用pop方法之前,需要确定路由栈中是否只有唯一的路由。)
既然将唯一的路由出栈并不能关闭app,那么如果想要关闭app的话该怎么做呢?
方法1:
SystemChannels.platform.invokeMethod('SystemNavigator.pop');
此方法在IOS上会被忽略,因为IOS不允许应用退出自己。
方法2:
import 'dart:io';
...
exit(0);
此方法会立即结束Dart虚拟机进程。副作用正如文档所说:This does not wait for any asynchronous operations to terminate. Using exit is therefore very likely to lose data.
canPop、maybePop
上面提到,为避免黑屏,在调用pop方法之前,需要确定路由栈中是否只有唯一的路由。那么该如何确定呢?答案是通过canPop函数。当路由栈中只有唯一的一个路由时,canPop会返回false,其他情况都会返回true。因此可以这样使用:
if(Navigator.canPop(context)){
Navigator.pop(context);
}
maybePop函数的情况比较复杂,它的行为在大部分情况下与if(Navigator.canPop(context)){Navigator.pop(context);}
相同,但却远不止于此。使用时需要谨慎。
popUntil
重复调用pop方法使路由栈中的路由逐一出栈,直到predicate函数返回了true。
Navigator.popUntil(context, ModalRoute.withName("Page2"));
popAndPushNamed
将当前路由出栈,并将一个新路由加入到栈顶。
replace、replaceRouteBelow
//以一个新路由替换一个路由栈中已有的路由。
Navigator.replace(context, oldRoute, newRoute);
//以一个新路由替换一个路由栈中已有的路由。被替换的路由是位于anchorRoute下的那个路由。
Navigator.replaceRouteBelow(context, anchorRoute, newRoute);
//被替换的路由永远不会变成completed状态,也就是说将其入栈的push、pushNamed的返回值future也不会变成completed状态。
//被替换的路由不能是可见的,因为替换过程没有任何动画过渡,看起来会比较古怪。
removeRoute、removeRouteBelow
将指定的路由从任务栈中移除。
Navigator.removeRoute(context, route);
Navigator.replaceRouteBelow(context, anchorRoute);
//被remove的路由永远不会变成completed状态,也就是说将其入栈的push、pushNamed的返回值future也不会变成completed状态。