目录
简介
我们在flutter中可以使用navigator.push或者navigator.pushnamed方法来向navigator中添加不同的页面,从而达到页面调整的目的。
一般情况下这样已经足够了,但是有时候我们有多个navigator的情况下,上面的使用方式就不够用了。比如我们有一个d88尊龙官网手机app主页面app的navigator,然后里面有一个匹配好友的功能,这个功能有多个页面,因为匹配好友功能的多个页面实际上是一个完整的流程,所以这些页面需要被放在一个子navigator中,并和主navigator区分开。
那么应该如何处理呢?
搭建主navigator
主navigator是我们app的一些主要界面,这里我们有三个界面,分别是主home界面,一个setting配置界面和好友匹配界面。
其中好友匹配界面包含了三个子界面,这三个子界面将会用到子路由。
先来看下主路由,主路由的情况跟普通的路由没啥区别,这里我们首先定义和home和setting匹配的两个widget:homepage和settingspage:
class homepage extends statelesswidget { const homepage({ super.key, }); @override widget build(buildcontext context) { return scaffold( appbar: _buildappbar(context), body: center( child: padding( padding: const edgeinsets.symmetric(horizontal: 24.0), child: column( mainaxissize: mainaxissize.min, children: const [ sizedbox( width: 250, height: 250, child: center( child: icon( icons.home, size: 175, color: colors.blue, ), ), ), sizedbox(height: 32), text( '跳转到好友匹配页面', textalign: textalign.center, style: textstyle( fontsize: 24, fontweight: fontweight.bold, ), ), ], ), ), ), floatingactionbutton: floatingactionbutton( onpressed: () { navigator.of(context).pushnamed(routefriendmatch); }, child: const icon(icons.add), ), ); }
homepage很简单,它包含了一个floatingactionbutton,当点击它的时候会调用 navigator.pushnamed方法进行路由切换。
然后是settingspage,它是一个简单的column:
class settingspage extends statelesswidget { const settingspage({ super.key, }); @override widget build(buildcontext context) { return scaffold( appbar: _buildappbar(), body: singlechildscrollview( child: column( mainaxissize: mainaxissize.min, children: list.generate(8, (index) { return listtile( title: text('设置项$index'), ); }), ), ), ); }
最后一个页面是friendmatchflow,这个页面比较复杂,我们在下一个再进行讲解。
然后我们为主路由在ongenerateroute方法中进行定义:
void main() { runapp( materialapp( ongenerateroute: (settings) { late widget page; if (settings.name == routehome) { page = const homepage(); } else if (settings.name == routesettings) { page = const settingspage(); } else if (settings.name == routefriendmatch) { page = const friendmatchflow( setuppageroute: routefriendmatchpage, ); } return materialpageroute( builder: (context) { return page; }, settings: settings, ); }, debugshowcheckedmodebanner: false, ), ); }
主路由很简单,跟普通的路由没有太多的区别。
构建子路由
接下来是构建子路由的步骤。在主路由中,如果路由的名称是routefriendmatch,那么就会跳转到friendmatchflow。
而这个flow页面实际上是由几个子页面组成的:选择好友页面,等待页面,匹配页面和匹配完毕页面。
具体的页面代码这里就不写了,我们主要来讲一下子路由的使用。
对于friendmatchflow来说,它本身是一个navigator,所以我们的build方法是这样的:
widget build(buildcontext context) { return willpopscope( onwillpop: _isexitdesired, child: scaffold( appbar: _buildflowappbar(), body: navigator( key: _navigatorkey, initialroute: widget.setuppageroute, ongenerateroute: _ongenerateroute, ), ), ); }
因为他需要根据用户的不同点击来进行内部路由的切换,所以需要保存对当前子navigator的应用,所以这里friendmatchflow是一个statefulwidget,并且上面的_navigatorkey是一个globalkey对象,以提供对子navigator的引用:
final _navigatorkey = globalkey();
这里的_ongenerateroute方法,跟主路由也是很类似的,主要定义的是子路由中页面的跳转:
route _ongenerateroute(routesettings settings) { late widget page; switch (settings.name) { case routefriendmatchpage: page = waitingpage( message: '匹配附近的好友...', onwaitcomplete: _ondiscoverycomplete, ); break; case routefriendselectpage: page = selectfriendpage( onfriendselected: _onfriendselected, ); break; case routefriendconnectingpage: page = waitingpage( message: '匹配中...', onwaitcomplete: _onconnectionestablished, ); break; case routefriendfinishedpage: page = finishedpage( onfinishpressed: _exitsetup, ); break; }
这里的on***selected是voidcallback回调,用来进行路由的切换:
void _ondiscoverycomplete() { _navigatorkey.currentstate!.pushnamed(routefriendselectpage); } void _onfriendselected(string deviceid) { _navigatorkey.currentstate!.pushnamed(routefriendconnectingpage); } void _onconnectionestablished() { _navigatorkey.currentstate!.pushnamed(routefriendfinishedpage); }
可以看到上面的路由切换实际上是在子路由上切换,跟父路由无关。
如果想要直接从子路由跳出到父路由该怎么处理呢?很简单,调用navigator.of的pop方法即可:
void _exitsetup() { navigator.of(context).pop(); }
这里的context默认是全局的context,所以会导致主路由的跳转变化。
总结
以上的代码运行结果如下:
虽然上面的例子看起来复杂,但是大家只要记住了不同的路由使用不同的navigator范围进行跳转就行了。