相关类分析
BuildContext
一个指向小控件树中小控件位置的句柄。见BuildContext 文档
BuildContext对象被传递给WidgetBuilder函数(如StatelessWidget.build),并可从State.context成员中获得。一些静态函数(如showDialog、Theme.of等)也采用BuildContext,以便它们可以代表调用小控件执行操作,或获取特定于给定上下文的数据
每个widget都有自己的BuildContext,它成为StatelessWidget.build或State.build函数返回的那个widget的父节点。(同样地,也是RenderObjectWidget的任何子节点的父节点。)
需要特别注意,build方法所在的widget的BuildContext与该build方法返回的widget的BuildContext是不同的。如果需要那个被返回的控件树的子控件的BuildContext,可以使用 Builder 小控件,则传递给 Builder.builder 回调的BuildContext将是 Builder 本身的上下文。
随着小控件在树上移动,特定小控件的 BuildContext 可以随时间改变位置。正因为如此,从该类上的方法返回的值不应在执行单个同步函数之后被缓存。BuildContext对象实际上就是Element对象。BuildContext接口是用来阻止直接操作Element对象的。
BuildContext的常见方法
dependOnInheritedWidgetOfExactType({Object aspect}) → T 获取给定类型T的最近的widget,该widget必须是一个具体的InheritedWidget子类的类型,并将此构建上下文注册到该widget中,这样当该widget发生变化时(或引入该类型的新widget,或该widget消失),此构建上下文将被重建,以便它可以从该widget中获取新的值。
findAncestorRenderObjectOfType() → T 返回最近的祖先
RenderObjectWidget小控件的RenderObject对象,该对象是给定类型 T 的实例。不应从build方法中使用此方法,调用此方法比较耗费性能。findAncestorStateOfType<T extends State<StatefulWidget>>() → T返回给定类型T的实例的最近祖先
StatefulWidget控件的State对象。不应从build方法中使用此方法,调用此方法比较耗费性能。findAncestorWidgetOfExactType() → T 返回给定类型T的最近祖先Widget,它必须是具体Widget子类的类型。调用此方法比较耗费性能。
findRenderObject() → RenderObject当前小控件的
RenderObject。如果小控件是RenderObjectWidget,则这是小控件为其自身创建的渲染对象。否则,它是第一个后代RenderObjectWidget的渲染对象 。findRootAncestorStateOfType<T extends State<StatefulWidget>>() → T返回给定类型 T 的最远祖先
StatefulWidget控件的State对象。getElementForInheritedWidgetOfExactType() → InheritedElement 获取给定类型T的最近的widget对应的元素,它必须是一个具体的
InheritedWidget子类的类型。如果没有找到这样的元素,则返回null。visitAncestorElements(bool visitor(Element element)) → void从此
context的小控件的父级开始遍历祖先链,为每个祖先调用参数。回调被赋予对祖先小控件的相应Element对象的引用。当到达根部小控件或回调返回false时,遍历停止。回调不得返回null。这对于检查小控件树很有用。visitChildElements(ElementVisitor visitor) → void遍历此小控件的子级。这对于在子节点被构建后应用更改而无需等待下一帧非常有用,尤其是当子节点是已知的,且只有一个子节点时(StatefulWidgets 或 StatelessWidgets 总是如此)。递归调用此方法非常耗费性能,应尽可能避免。
Element
Element实际上就是BuildContext的实现类。见Element 文档
Element的属性
| 属性 | 类型 | 简述 |
|---|---|---|
| depth | int |
保证大于父级的整数(如果有)。树根元素的深度必须大于0。 |
| dirty | bool |
如果该元素被标记为需要重建,则返回true。 |
| owner | BuildOwner |
管理该Element生命周期的对象。 |
| renderObject | RenderObject |
树中此位置(或下方)的渲染对象。如果此对象是一个RenderObjectElement,那么渲染对象就是树中这个位置的对象。否则,这个getter方法将沿着树向下走,直到找到一个RenderObjectElement为止。 |
| size | Size |
返回的RenderBox的大小。这个getter方法只有在布局阶段完成后才会返回一个有效的结果。因此,从build中调用这个函数是无效的 |
| slot | dynamic |
由父级设置的信息,用于定义此子级在其父级的子级列表中的位置。仅具有一个子级的Element子类,则该子类的slot应该使用null。 |
| widget | Widget |
该Element的配置。 |
Element updateChild(Element child, Widget newWidget, dynamic newSlot)使用给定的新配置(newWidget)更新给定的子元素(child)
| newWidget == null | newWidget != null | |
|---|---|---|
| child == null | 返回null | 返回一个新的Element |
| child != null | 旧的子元素(child)被移除,返回null | 若可能,更新旧的子元素(child),返回child 或新的Element |
Element inflateWidget(Widget newWidget, dynamic newSlot)为给定的widget创建一个element,并将其作为该element的子元素添加到给定的Slot中。如果给定widget具有
global key,并且已经存在具有该全局键的widget的元素,则此函数将重用该元素(可能从树中的另一个位置移植它,或者从非活动元素列表中重新激活它),而不是创建一个elementvoid mount(Element parent, dynamic newSlot)在给定的父元素的给定Slot位中添加这个元素。当新创建的元素第一次被添加到树上时,框架会调用这个函数,将Element从"initial"生命周期状态转换到 "active"生命周期状态
void update(covariant Widget newWidget)更改用于配置此Element的widget。当父元素希望使用不同的widget来配置这个元素时,框架会调用这个函数。新的widget保证与旧的widget具有相同的runtimeType。该函数仅在"active"生命周期状态下被调用。
updateChild 和 inflatWidget 主要作用是当Widget树发生变化时, 创建对应的Element。 不同的是updateChild做了一些优化,尽可能地复用之前的旧Element。 只有在无法复用的情况下,才调用inflatWidget去直接创建一个Element。 通常新创建一个Element时,会马上调用mount方法。 如果可以复用的场景,则调用update()方法
当新的Widget和旧Widget相同,或者新的Wiget和旧Widget类型相同,且key相同(如果key都为空也表示相同)时,可复用Element
Widget
是一个用于描述Element的配置。
Widget是Flutter框架中的核心类层次结构。是用户界面部分的不变描述。可以将Widget扩充为Element,以管理底层渲染树。
Widget本身没有可变的状态(它们的所有字段都必须为final)。如果希望将可更改的状态与Widget关联起来,请考虑使用StatefulWidget,每当它扩充成一个Element并被合并到树中时,它就会创建一个State对象(通过StatefulWidget.createState)。

RenderObject
渲染树中的对象。见RenderObject 文档
RenderObject具有一个parent属性,并具有一个名为parentData的插槽,父RenderObject可以在其中存储特定于孩子的数据,例如,孩子的位置。 RenderObject类还实现基本的布局和绘制协议。
然而,RenderObject类并没有定义子模型(例如,一个节点是否有零个、一个或多个子节点)。它也没有定义坐标系(例如子节点是以笛卡尔坐标定位,还是以极坐标定位等),也没有定义具体的布局协议。它的子类RenderBox引入了布局系统并使用笛卡尔坐标系。
通常,Flutter渲染对象树的根是RenderView。 该对象有一个child,必须是RenderBox。因此,如果你想在渲染树中拥有一个自定义的RenderObject子类,你有两个选择:要么你需要替换RenderView本身,要么你需要一个继承自RenderBox的自定义类。 (后者是更常见的情况。)
关于布局
布局协议从Constraints类派生。
performLayout方法应该接受约束,并应用它们。布局算法的输出是在对象上设置的字段,这些字段描述了对象的几何形状,以便于父类的布局。例如,对于RenderBox,输出是RenderBox.size字段。仅当父级在子级上调用layout时并将parentUsesSize指定为true时,此输出才应由父级读取。只要渲染对象上发生任何会影响该对象布局的更改,则应调用markNeedsLayout
Layer
参见 Layer 文档
图层类。在绘制过程中,渲染树生成一棵合成图层树,这些图层被传到到引擎中并由合成器显示。此类是所有图层的基类。大多数图层可以更改其属性,并且可以将图层移动到其他父对象
要合成树,需创建一个SceneBuilder对象,将其传递给根Layer对象的addToScene方法,然后调用 SceneBuilder.build获得一个Scene。然后可以使用Window.render来绘制一个Scene。
Scene对象代表合成场景的不透明对象。通过Window.render方法显示到屏幕上。实际上它是上层框架和底层引擎之间传递的数据结构,对应 Engine中的 scene.cc 结构。
BuildOwner
Widget框架的管理类。
该类跟踪哪些widget需要重建,并处理其他适用于widgets树的任务,如管理树的非活动元素列表,并在调试时的热重载期间在必要时触发 "reassemble "命令。
主构建所有者通常由WidgetsBinding拥有,并与构建/布局/绘制管道的其余部分一起由操作系统驱动。
可以构建其他构建所有者来管理屏幕外的小组件树。
要为树分配构建所有者,请在小组件树的根元素上使用 RootRenderObjectElement.assignOwner 方法。

PipelineOwner
用于管理渲染管道。
管道所有者提供了一个驱动渲染管道的接口,并存储了关于在管道的每个阶段中哪些渲染对象请求被访问的状态。

公众号“编程之路从0到1”