路由(Route)在移动开发中一般指页面(Page),在Android中一般指一个Activity。路由管理,就是管理页面之间如何跳转,一般也可被称为导航管理。在Flutter中,不一样页面之间进行切换和发送数据,这些页面被称为Route(路由),是由一个Navigator的小部件进行管理。Flutter中的路由管理和原生开发相似,导航管理都会维护一个栈,入栈(push)操做对应打开一个新页面,出栈(pop)操做对应页面关闭操做,而路由管理主要是指如何来管理路由栈。bash
建立一个Flutter应用,启动以后点击按钮跳转一个新的页面。markdown
class HomePage extends StatefulWidget { @override _HomePage createState() { // TODO: implement createState return _HomePage(); } } class _HomePage extends State<HomePage> { @override Widget build(BuildContext context) { // TODO: implement build return Center( child: GestureDetector( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) { return PageA(); }, ), ); }, child: Text("HomePage"), ), ); } } class PageA extends StatefulWidget { @override _PageA createState() { // TODO: implement createState return _PageA(); } } class _PageA extends State<PageA> { @override Widget build(BuildContext context) { // TODO: implement build return Center( child: Text("PageA"), ); } } 复制代码
要想使用命名路由,咱们必须先提供并注册一个路由表(routing table),这样应用程序才知道哪一个名字与哪一个路由组件相对应。其实注册路由表就是给路由起名字,路由表的定义以下: Map<String, WidgetBuilder> routes;
它是一个Map,key为路由的名字,是个字符串;value是个builder回调函数,用于生成相应的路由widget。咱们在经过路由名字打开新路由时,应用会根据路由名字在路由表中查找到对应的WidgetBuilder回调函数,而后调用该回调函数生成路由widget并返回。 咱们能够在MaterialApp
中注册路由表:app
class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(title: 'Flutter Demo Home Page'), routes: { "/home":(context)=>HomePage(), "/a":(context)=>PageA(), "/b":(context)=>PageB(), "/c":(context)=>PageC(), }, ); } } 复制代码
了解了路由的基本使用和跳转以后,咱们来看一下Navigator中基本的方法: less
Flutter使用一个堆栈来管理路由,push为入栈,将元素添加到堆栈的顶部,相应的pop为出栈,同一堆栈中删除顶部元素。在Flutter总,push和pop,已经能够胜任咱们大多数的业务场景了。push和pushNamed的基本使用咱们已经在上文讲过了,Navigator的各个静态方法的使用基本和这二者相似。下面咱们对其中的每一个方法作一个简单的介绍:ide
当咱们要结束当前页面,返回上一页面时,咱们可使用pop让路由出栈: Navigator.pop(context);
若是须要有返回参数给上一页面: Navigator.pop(context,"返回的数据");
相应的,须要在修改跳转的:函数
Navigator.push( context, MaterialPageRoute( builder: (context) { return PageA( name: "wall", age: "13", ); }, ), ).then((v) { //接收目标页面返回的参数 setState(() { a = v; }); }); 复制代码
在then里接收第二个页面返回的参数,并使用setState刷新页面 canPop能够用来判断页面是否被弹出,根据官方的教程,初始化路由页面没法被pop,也就是说当栈内只有一个路由时,改方法会返回false,其余时刻返回true。ui
maybePop
能够理解为canPop的升级版,canPop只用来判断页面是否能够被pop。而maybePop则对此进行了升级——若是能够pop则直接pop,不然什么都不作。this
if (Navigator.canPop(context)) { Navigator.pop(context); } else { //nothing } 复制代码
也就是说当前页面能返回就返回,返回不了就拉倒。 popUntil
做用是反复执行pop 直到返回到咱们指定的页面为止,popUntil接收一个函数,等到该函数的参数predicate返回true为结束pop操做: Navigator.popUntil(context, ModalRoute.withName('/a'));
假如原来的页面顺序为a->b->c->d,执行完上述代码后为:a。 spa
pushReplacement
和pushReplacementNamed
的功能一致,它们两者的区别与push
和pushNamed
的区别同样——前者直接将页面入栈,后者经过路由命名的名字将页面入栈。这两对的使用方法也一致,不一样的是pushReplacement
和pushReplacementNamed
不是讲新的页面直接入栈,而是替换掉栈顶的页面。类比Android原生能够理解为:在启动新的Activity时,finish()掉当前页面。code
Navigator.of(context).pushReplacementNamed('/d'); 复制代码
同上,二者的区别不在赘述,它们的实现的功能为:向栈添加新的路由,并删除全部先前的路由,直到路由为指定的路由为止——例如在退出登陆时咱们能够直接清除栈内的页面返回首页。用法以下:
Navigator.pushNamedAndRemoveUntil(context, "/a",ModalRoute.withName("/a")); 复制代码
假如原来的页面顺序为a->b->c->d,执行完上述代码后为:a->a。
removeRoute
表示从Navigator中删除路由,同时执行Route.dispose释放Route自身资源,路由的生命周期结束。 removeRouteBelow
从Navigator中删除路由,同时执行Route.dispose操做,要替换的路由是传入参数anchorRouter里面的路由。
replace
将Navigator中的路由替换成一个新路由。 replaceRouteBelow
将Navigator中的路由替换成一个新路由,要替换的路由是是传入参数anchorRouter里面的路由。
普通路由中的传参以下所示:
Navigator.push(context, MaterialPageRoute(builder: (context) => Less(name: "new"))); //在新的Widget的构造方法里接受参数: class Less extends StatelessWidget { final String name; Less({Key key, this.name}) : super(key: key){ print("无状态组件$name:建立了"); } } 复制代码
对于页面数据的回调,除了上文中讲的,还可使用方法传递的方式实现:直接将父Widget的方法传递给子Widget,在新的Widget里调用传递过来的方法更新数据。 命名路由的传参有些许复杂:
//携带参数跳转 Navigator.pushNamed(context, "/a", arguments: {"name": "name"}); //在目标页面取值 Map arguments2 = ModalRoute.of(context).settings.arguments; 复制代码
还有一种方案是在 onGenerateRoute 回调中利用URL参数自行处理。 路由跳转时写入参数:
onGenerateRoute: (RouteSettings settings) { WidgetBuilder builder; if (settings.name == '/a') { builder = (BuildContext context) => new Full(); } return new MaterialPageRoute(builder: builder, settings: settings); }, 复制代码
差很少絮叨完了,基本上只是方法罗列,进一步的探索和封转我也还在探索之中。最后,画图真难,谁有Mac下好的画图软件推荐啊。