命名路由与动态路由
Flutter中的路由分为命名路由和动态路由两种
- 动态路由 我们一般会这样写
Navigator.push( context,
MaterialPageRoute(builder: (context) {
return DetailPage();
}));
},
)
复制代码
- 命名路由
- 注册路由表
routes:{
"detail_page":(context) => DetailPage(),
"/":(context) => MyHomePage(title: 'app首页')
}
复制代码
- 路由跳转
Navigator.pushNamed(context, "detail_page",{Object arguments})
复制代码
这两种路由的的特点
- 动态路由:分散式管理 每次进行路由跳转操作的时候都要导入目标路由的头文件
优势:依赖编译器,当目标路由名字或者参数有改动的情况下,编译器可以直接检测出错误。 - 命名路由:集中式管理 路由跳转的时候只需要传入路由表中的注册的key值就可以
优势: 跳转不需要导入头文件,可以通过硬编码的方式进行跳转,语义更加明确
以我个人经验来看,开发中更推荐的方式还是使用命名路由。当然没有是绝对正确或者错误的,清楚了两者的优劣之后,结合自己当前的业务 才能做出明智的选择。
这两种路由在使用上有很大的区别,那么在实现原理上有什么区别么?为了描述清楚这个问题 我画了一张图,如下。
从上图可以看出在实现上 其实命名路由就行根据传入的 name
找到对应的router
然后调用了动态路由的方法,所以没有啥本质区别,这样设计的好处就是,动态路由和命名路由是互相兼容的,这种编程方式值得借鉴学习。
Navigator 1.0存在的问题
上面那张图有一个 _history
的数组,这数组可能有人会称之为路由栈,但是这里要强调下我们平时所说的路由栈,其数据结构使用的数组(array
),而不是栈(stack
)。
但是这个_history
是私有的 不允许外部类进行操作,如果你想操作_history
只能通过系统提供的 push
pop
pushReplacement
等方法。所以1.0存在的问题就是 不能够灵活的操作这个 _history
。假设我们有这样的一个业务
通过一个网页唤起我们的app 然后一次进入 ScreenA -> ScreenB -> ScreenC 最终停留在ScreenC,但是我希望用户是直接看到ScreenC 并不是看到从ScreenA到 ScreenC的转场,基于这种业务情况也许Navigation 1.0也可以实现,就是通过push操作 然后禁掉转场动画,似乎也可以实现,但是如果可以直接操作_history似乎会更优雅一点,比如我们可以用如下方式进行跳转
Navigator.pushNamed(context, "/ScreenA/ScreenB/ScreenC")
复制代码
如果我还想传入参数怎么办呢 ,我们可以这样写
Navigator.pushNamed(context, "/ScreenA/ScreenB/ScreenC?name=zhansan&age=12")
复制代码
咦?好熟悉的感觉 这看起来就很像web端的链接了。
不过这在1.0的时候可不太好实现,于是Flutter推出了Navigator2.0
Navigator 2.0是如何满足更复杂的业务情况
那么在Navigator 2.0里面,Flutter是如何解决这个问题的呢?可能最简单的方式就是把 _history
从私有的变成公有的。但是这样话 _history
又会变的很危险,我认为这对上线的应用可能会有很大的潜在风险
所以在Navigator 2.0里面Flutter用一种更委婉的方式解决这个问题,为了展示这个过程我画了下面的这张图
也就是说 Navigator传入了一个叫做pages
的列表,然后将pages数组中的元素通过_history.addAll()
方法转化为_history
,那么开发者就可以通过操作pages
这个数组从而达到操作_history
的目的,这样的设计还有一个好处就是 Navigator 2.0完全兼容 Navigator 1.0,因为究其原理,最终我们通过 push
pop
等,其实都是在操作 _history
者数组,这与1.0的设计完全吻合
那么既然我们可以自由的操作pages
那么关于上面那个业务场景我们就可以这样实现
pages.add(ScreenA)
pages.add(ScreenB)
pages.add(ScreenC)
这样在ScreenA
ScreenB
ScreenC
就可以不通过 push
这个方法 添加到了 _history
中了。
原理解释清楚了,剩下的就是编写代码了,至于Navigator 2.0 中设计到的API 以及如何使用可以前往github.com/coder-dongj…
下载代码自行查看
最后: 这世界上最遥远的距离就是知道和做到