大前端开发中的路由管理之五:Flutter篇

2021-11-18 10:40:07 浏览数 (1)

        前面大家了解了Web和Native端的路由管理,这篇文章出场的是大前端领域备受开发者喜欢的新秀Flutter。

        Flutter作为一款跨平台UI框架,借鉴了React(Web开发框架)的响应式的UI框架设计思想等。在Flutter中,一切皆是Widget(组件),其中StatefulWidget(有状态的组件)和React中的组件类似,可以通过数据变化去手动更新视图,Flutter路由管理实现的核心组件Navigator就是这样的一个StatefulWidget。

1、认识Flutter路由导航

1.1  Route(路由页面)

页面的包装类,一个页面想要被路由统一管理,必须包装为一个Route,Route并不是一个widget,但是在页面栈实现中起到至关重要的作用,它是一个抽象类,其继承关系如下,其中每一层都处理了与其相关的一些逻辑。

  • OverlayRoute:在导航器的Overlay中显示控件的路由。主要将路由转换为Widget插入控件树。
  • TransitionRoute:具有进入和退出过渡动画的路由。主要处理路由过渡动效。
  • ModalRoute:阻止与下层路由交互的路由。它覆盖整个导航器。但它们不一定是不透明的。例如一个对话框。主要处理事件的拦截。
  • PageRoute:替换整个屏幕的模态路由。由它派生出了我们熟悉的MaterialPageRoute,主要用于Flutter的页面切换。
  • PopupRoute:在当前路由上覆盖Widget的模态路由。主要用于弹出框,对话框之类。

1.2  Navigator(导航器)

管理所有的Route的Widget,实现路由导航的核心widget。它维护了一个路由栈集合(List<_RouteEntry>),当你调用push,pop方法时,Navigator都会以栈的方式对这个集合进行添加或删除,并通过路由栈状态变化实现对页面栈的更新。

  • 我们不需要手动创建Navigator,开发中使用的MaterialApp、CupertinoApp、WidgetsApp它们默认是有插入Navigator的,我们在需要的时候可以直接使用Navigator.of(context)。Navigator的widget构建流程如下: 
  • 当我们想使用导航操作时,Navigator提供了如下几个常用的方法:
代码语言:javascript复制
// 路由跳转:传入一个路由对象Future<T> push<T extends Object>(Route<T> route)
// 路由跳转:传入一个名称(命名路由)Future<T> pushNamed<T extends Object>(  String routeName, {    Object arguments,  })
// 路由返回:可以传入一个参数bool pop<T extends Object>([ T result ])

1.2  Overlay(页面栈)

真正的页面栈,Overlay可以翻译为叠加层或覆盖层。按照官方的解释,它是一个可以独立管理的覆盖层堆栈。它维护一个页面栈集合(List<OverlayEntry>),实现页面栈到widget的转换过程,它同时也拥有一个私有类_Theatre来进行页面widget的绘制。

  • _Theatre:它的名字非常形象的表达了它的功能:剧院。你有很多组件以一层层覆盖的模式绘制在界面上时,如果其中某一层的组件以全屏不透明的模式绘制在界面上,那它下层的组件就不需要再进行绘制了。

2、Flutter路由管理实现

2.1 导航器初始化

        Navigator是一个有状态的widget,NavigatorState在初始化时主要做了两件事:

  1. 根据配置参数创建初始化路由,初始化路由会放入_history(路由栈)里面去
  2. 调用_flushHistoryUpdates方法刷新路由栈

        这里最为复杂也是最核心的就是这个刷新路由栈的方法,该方法会根据不同的路由生命周期(_RouteLifecycle)做相应处理。初始化创建的路由会设置其路由状态为_RouteLifecycle.add,在_flushHistoryUpdates中会调用route的插入方法将根路由转换为OverlayEntry对象,插入到Overlay管理的页面栈中并通知Overlay更新视图。下面是伪代码,可以简单了解一下:

代码语言:javascript复制
// [NavigatorState] 伪代码List<_RouteEntry> _history = <_RouteEntry>[]; // 路由栈集合void initState() {  _history.addAll([_RouteEntry(route, _RouteLifecycle.add)]);// 1.依据初始化构建参数创建初始化路由_RouteEntry,放入_history集合  _flushHistoryUpdates(); // 2.更新页面栈}void _flushHistoryUpdates() {  // 1.遍历路由栈集合  // 2.状态为_RouteLifecycle.add的路由调用  while(遍历条件) {    switch (路由状态) {      case _RouteLifecycle.add: // 执行add对应方法 初始化跟路由会执行      case _RouteLifecycle.push: // 执行push动作对应方法      ...    }  }  // 3.对应路由监听器触发,无用路由和页面销毁,overlay组件更新}Widget build() {  // 构建Overlay 并通过一个_overlayKey持有OverlayState}

2.2 页面绘制

        Overlay在Navigator的build方法中创建,Overlay会遍历OverlayEntry列表,将保存的实体信息对象封装为_OverlayEntryWidget控件,最终将包含_OverlayEntryWidget的列表交给_Theatre控件插入控件树中用于渲染。

        _Theatre控件将页面分为了两种,一种是舞台上的(onstage)演员,另一种则是舞台下的(offstage)观众。当某个包装页面的OverlayEntry的opaque属性为true时,表示占满全屏且不透明,那么以它为分界线,它之下的所有页面都不需要绘制了(因为被挡住了看不见)。如果OverlayEntry的maintainState属性也为true,则被分到舞台下的观众那一组,否则,没有进入剧院的资格。

2.3 导航操作

        前面我们了解了Navigator的初始化构建流程,对于页面栈刷新已经有了一些认识,接下来我们来看看push方法都做了些什么。

代码语言:javascript复制
Future<T> push<T extends Object>(Route<T> route) {  // 使用_RouteEntry包装传进来的路由然后入栈,设置路由状态为push  _history.add([_RouteEntry(route, _RouteLifecycle.push)]);  _flushHistoryUpdates();// 刷新路由栈  ...}

        在刷新路由栈的时候push状态的路由也会插入两个新的OverlayEntry,并在所有操作完成后触发Overlay更新。下图是push前后各widget中的栈的变化。

3、Flutter路由管理实现总结

        从以上流程实现可以看出,Flutter页面栈的实现依赖于:

  • Navigator持有路由栈,提供导航方法,当路由栈发生变化时同步更新页面栈。
  • Overlay持有页面栈,它实现页面栈到渲染用widget集合的转换过程,并能够接受到路由栈更新的通知去同步更新视图。
  • _Theatre负责对页面widget进行动态构建和绘制,保证渲染性能。

        上面讲到是纯Flutter中路由管理的实现,但是在我们开发中可能还会遇到Flutter-Native混编的模式,对这块感兴趣的同学们可以在我们团队这篇文章 Flutter 核心原理与混合开发模式 中解锁更多知识。


至此,我们了解到了Flutter端是如何去实现路由管理的,那么,就请期待我们最后一篇文章《大前端开发中的路由管理之六:总结篇》

参考资料

[1]  Flutter路由源码剖析

https://zhuanlan.zhihu.com/p/208788731

[2] Flutter路由导航

https://zhuanlan.zhihu.com/p/144820879

QQ音乐招聘 Android / iOS 客户端开发,点击左下方“查看原文”投递简历~

也可将简历发送至邮箱:tmezp@tencent.com


文末为大家推荐一个技术号《腾讯音乐天琴实验室》,TME天琴实验室致力于对业内前沿科技如AI等方向进行相关研发,持续推出新技术提升TME旗下QQ音乐等平台的音乐视听体验,对音视频相关AI研发感兴趣的同仁们一起交流学习起来吧!!!

↓   ↓   ↓

0 人点赞