常见组件

  • [StatefulWidget](有状态组件),对于那些可以在其生命周期内多次根据状态创建不同效果的小组件。
  • [InheritedWidget](继承式组件),用于引入环境状态的部件,这些状态可以被后代的部件所读取。
  • [StatelessWidget](无状态组件),对于那些总是使用特定配置和环境状态构建的小组件。
  • [RenderObjectWidget](渲染对象组件),为 RenderObjectElements 提供配置,RenderObjectElements 封装了 RenderObjects,RenderObjects 提供应用程序的实际渲染。
  • [MultiChildRenderObjectWidget]

三棵树

三棵树

Widget 树

平时使用 Widget 声明式的形式写出的界面,可以理解为 Widget 树。简单的说,Widget 存在的作用等同于一个配置文件,将根据这个配置文件创建 Element Tree

组件关系

Element 树

Element

Widget 树是非常不稳定的,动不动就执行 build 方法,一旦调用 build 方法意味着这个 Widget 依赖的所有其他 Widget 都会重新创建,如果 Flutter 直接解析 Widget树,将其转化为 RenderObject 树来直接进行渲染,那么将会是一个非常消耗性能的过程,那对应的肯定有一个东西来消化这些变化中的不便,来做cache。因此,这里就有另外一棵树 Element 树。Element 树这一层将 Widget 树的变化(类似 React 虚拟 DOM diff)做了抽象,可以只将真正需要修改的部分同步到真实的 RenderObject 树中,最大程度降低对真实渲染视图的修改,提高渲染效率,而不是销毁整个渲染视图树重建。

TODO:组件中的 context 实际上就是与组件对应的 Element 对象。

TODO:ComponentElement 为非渲染 Widget 对应的 Element,RenderObjectElement 为渲染 Widget 对应的 Element

RenderObject 树

Flutter 引擎需要把我们写的 Widget 树的信息都渲染到界面上,这样人眼才能看到。跟渲染有关的当然有一颗渲染树 RenderObject Tree,渲染树节点叫做 RenderObject,负责处理布局、绘制相关工作,包含组件尺寸、位置等重要信息。

TODO:只有需要渲染的 Widget 才会在 RenderObject Tree 中拥有对应的节点。例如继承自 StatelessWidget & StatefulWidget 的 Widget 只是将其他 Widget 做一个组合,组件本身并不需要显示,因此在 RenderObject 树上不会有相对应的节点。

TODO:布局和绘制分为两个步骤,尺寸约束只存在于布局流程中,绘制步骤中没有强制性限制。

参考资料