300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > Flutter之路由系列之Navigator简析

Flutter之路由系列之Navigator简析

时间:2023-03-13 04:46:36

相关推荐

Flutter之路由系列之Navigator简析

博主的博客Flutter之路由系列之LocalHistoryRoute简单的梳理下Flutter的路由机制,其中Navigator扮演者重要的角色。本篇博文就简单梳理下Navigator的相关知识点。闲言少叙,开始发车。

通过本篇博客你可以了解到:

1、MaterialApp内置了一个Navigator对象

2、一个APP中有多个Navigator对象在调用Navigator.of(context)要注意的事项

本篇通过一个demo app来说明Navigator的用法及其细节,在我们的demo中有个四个页面:InitPage,PageOne,PageTwo,DefaultPage。

其中PageOne,PageTow和DefalutPage三个页面及其简单,就是在屏幕总展示了“Page One”,“Page Two”和“Defalut Page”的文本文字,比如Default Page的页面效果如下:

在我本篇的demo中(博文最后提供全部源码),启动的时候会先展示InitPage,然后自动展示PageOne,点击PageOne,跳到PageTwo,点击PageTwo,跳到DefaultPage。关于这几个页面的关系,咱们一步步分析,先来看看demo的入口方法:

1、配置MaterialApp的初始路由和路由表

void main() {runApp(MyApp());///程序入口}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(initialRoute: '/initPage',routes: {'/': (BuildContext context) => DefaultPage(),'/initPage': (BuildContext context) => InitPage(),},);}}

关于MaterialApp有一个要注意的地方:它包含了APP中的top level 或者全局的Navigator对象,因为MaterialApp其内部内置了Navigator对象。另外MyApp还做了如下工作:

1、初始化了MaterialApp的initialRoute属性,该属性为String类型,代表着初始路由的Name

2、配置了MaterialApp的路由表routes属性,该属性是一个Map集合,key代表着路由的Name,Value代表着对应的Page

配置routes的时候,DefaultPage对应的路由名字是"/",代表默认路由;而InitPage对应的路由名字是“/initPage”,因为initialRoute属性设置为“/initPage”,所以我们的demo app运行起来的时候,首先展示的就是InitPage,所以来看看InitPage是什么。

注意此时内置的路由表的有两个路由,一个是默认路由“/”,一个是“/initPage”路由。

2、InitPage中Navigator使用方法

因为Navigator也是是个Widget,确切的来说是一个StatefulWidget.所以在InitPage中我们直接使用了Navigator作为UI展示,InitPage的代码如下:

class InitPage extends StatelessWidget {@overrideWidget build(BuildContext context) {///直接返回了一个Navigator对象return Navigator(//初始路由的名字initialRoute: 'pageOne',onGenerateRoute: (RouteSettings settings) {WidgetBuilder builder;switch (settings.name) {case 'pageOne'://pageOne的路由对应的页面builder = (BuildContext ctx) => PageOne();break;case 'pageTwo'://pageTwo的路由对应的页面builder = (BuildContext ctx) => PageTwo(onSignupComplete: () {///PageTwo点击事件,跳转到DefaultPage页面//注意这个Navigator.of操作的是MaterialApp的内置Navigator,后面会有说明Navigator.of(context).pop();},);break;}return MaterialPageRoute(builder: builder, settings: settings););}}

可以看出InitPage的build方法直接返回了Navigator,通过上面的的讲解我们知道MaterialApp也内置了一个Navigator对象,那么问题来了:

InitPage的Navigator对象和MaterialApp的Navigator对象,有啥区别和联系呢?这个问题会在后面的分析中说明,在这里读者可以留个心眼.

在InitPage 中我们为Navigator配置了如下属性:

1、initialRoute设置为pageOne

2、onGenerateRoute:根据路有配置RouteSettings 来展示不同的页面Page One 和Page Two,因为initialRoute配置为pageOne,所以APP 启动的时候就优先展示Page One.:

当我们调用Navigator.of(context).pushReplacementNamed(‘pageTwo’)或者Navigator.of(context).pushNamed(‘pageTwo’)的时候,就会走onGenerateRoute的case 'pageTwo'分支:

case 'pageTwo'://pageTwo的路由对应的页面builder = (BuildContext ctx) => PageTwo(onSignupComplete: () {///PageTwo点击事件,跳转到DefaultPage页面//注意这个Navigator.of操作的是MaterialApp的内置Navigator,后面会有说明Navigator.of(context).pop();},);break;

3、onGenerateRoute最终返回了MaterialPageRoute

2.1 PageOne的简单实现

再来看看PageOne的代码,PageOne页面展示了“Page One”文本和一个点击事件,当点击的时候跳转到PageTwo页面:

class PageOne extends StatelessWidget {@overrideWidget build(BuildContext context) {return DefaultTextStyle(child: GestureDetector(onTap: () {///替换PageOne页面,展示PageTwo//注意这个Navigator.of操作的是InitPage的Navigator,后面会有说明Navigator.of(context).pushNamed('pageTwo');},child: Text('Page One'),),);}}

在PageOne中调用了Navigator.of(context).pushReplacementNamed('pageTwo')来展示Page Two,注意这个Navigator.of(Context)返回的对象是InitPage包含的那个Navigator对应的NavigatorState对象,而不是MaterialApp内置Navigator对应的NavigatorState对象

2.2 PageTwo的简单实现

PageTwo页面的主要功能是,点击页面的时候跳转到DefalutPage页面!但是其点击事件有个需要注意的地方,下面看源码:

class PageTwo extends StatelessWidget {const PageTwo({this.onSignupComplete,});final VoidCallback onSignupComplete;@overrideWidget build(BuildContext context) {return GestureDetector(//点击事件onTap:onSignupComplete,child: DefaultTextStyle(child: Text('Page Two'),),);}}

注意看上面PageTwo源码中build方法中的点击事件,我们是在InitPage中初始化的,代码如下(在这里称之为方式A):

///方式Acase 'pageTwo':builder = (BuildContext ctx) => PageTwo(点击事件onSignupComplete: () {Navigator.of(context).pop();},);break

为什么不直接写成如下所示呢?(在这里称之为方式B):

//方式BWidget build(BuildContext context) {return GestureDetector(//点击事件onTap: () {Navigator.of(context).pop();},child: DefaultTextStyle(child: Text('Page Two'),),);}

原因很简单,方式A和方式B的点击代码看起来完全一样都是执行Navigator.of(context).pop(),但是二者有着本质的区别:

方式A的Navigator.of(context)不等于方式B的Navigator.of(context)。更确切的来说是方式A的Navigator.of(context)返回的NavigatorState对象是属于MaterialApp内置的Navigator对象的,而方式B返回的Navigator.of(context)是属于InitPage包含的Navigator对象的,更直观的可以用下面代码来说明二者的区别:

如上图所以Navigator.of(context).pop(),是将InitPage弹出了路由,所以会展示DefaultPage.

而Navigator.of(ctx).pop()处理的是InitPage的路由逻辑,所以此时会将PageTwo弹出,而展示PageOne(因为前文说了在InitPage中先展示的是PageOne)。

到此为止Navigator的简单实用讲解完毕,如有不当之处,欢迎批评指正。下面是demo app的源码:

class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(title: 'Flutter Code Sample for Navigator',// MaterialApp contains our top-level NavigatorinitialRoute: '/initPage',routes: {'/': (BuildContext context) => DefaultPage(),'/initPage': (BuildContext context) => InitPage(),},);}}class InitPage extends StatelessWidget {@overrideWidget build(BuildContext context) {print("context=="+context.toString());// SignUpPage builds its own Navigator which ends up being a nested// Navigator in our app.return Navigator(initialRoute: 'pageOne',onGenerateRoute: (RouteSettings settings) {WidgetBuilder builder;switch (settings.name) {case 'pageOne':builder = (BuildContext ctx) => PageOne();break;case 'pageTwo':builder = (BuildContext ctx) => PageTwo(onSignupComplete: () {Navigator.of(context).pop();},);break;}return MaterialPageRoute(builder: builder, settings: settings);},);}}class DefaultPage extends StatelessWidget {@overrideWidget build(BuildContext context) {print("NavigatorpageTwo"+Navigator.of(context).toString());return DefaultTextStyle(style: Theme.of(context).textTheme.headline6,child: Container(color: Colors.white,alignment: Alignment.center,child: Text('Default Page'),),);}}class PageOne extends StatelessWidget {@overrideWidget build(BuildContext context) {return DefaultTextStyle(style: Theme.of(context).textTheme.headline6,child: GestureDetector(onTap: () {print("Navigator"+Navigator.of(context).toString());Navigator.of(context).pushNamed('pageTwo');},child: Container(color: Colors.lightBlue,alignment: Alignment.center,child: Text('Page One'),),),);}}class PageTwo extends StatelessWidget {const PageTwo({this.onSignupComplete,});final VoidCallback onSignupComplete;@overrideWidget build(BuildContext context) {return GestureDetector(onTap:onSignupComplete,child: DefaultTextStyle(style: Theme.of(context).textTheme.headline6,child: Container(color: Colors.pinkAccent,alignment: Alignment.center,child: Text('Page Two'),),),);}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。