一、Widget

组合类(Composite Widgets)

如Container、Scaffold、MaterialApp等,以及通过继承StatelessWidget和StatefulWidget的类。

代理类(Proxy Widgets)

如InheritedWidget,这是一种功能型组件,可以高效快捷地实现共享数据的跨组件传递;
InheritedWidget是一个代理类Widget,主要用于在Descendant Widgets之间传递共享信息;
通过使用InheritedWidget,可以在树结构中传递信息,当子类状态变更时,可以通知父类进行对应的变更;
ParentDataWidget主要用于配置Descendant Renderer Widget的布局信息;
与InheritedWidget的作用方向相反,ParentDataWidget为具有多个子类的RenderObjectWidget提供对应的配置等,例如Stack使用已定位好的父类Widget来定位每个子Widget。

绘制类(Render Object Widgets)

这类Widget几乎涵盖了屏幕上看到的所有UI,都是通过继承RenderObjectWidget实现的;
根据对应的Element,可以分为MultiChildRenderObjectWidget、SingleChildRenderObjectWidget和LeafRenderObjectWidget,其中LeafRenderObjectWidget是那些没有子节点的Widget。

StatefulWidget生命周期

可以分为三个阶段:创建、更新和销毁;
在创建阶段中,Widget会触发一系列生命周期方法来响应不同的事件;
这些方法包括createState、initState、didChangeDependencies和build;
createState方法会在Widget被创建时调用,用于创建一个新的State对象;
initState方法会在State对象被创建后调用,用于初始化State对象。didChangeDependencies方法会在State对象依赖的对象发生变化时调用,例如父Widget发生变化时;
build方法会在创建阶段和更新阶段都会被调用,用于构建UI界面;

在更新阶段中,Widget会触发一系列生命周期方法来响应不同的事件;
这些方法包括didUpdateWidget和setState;
didUpdateWidget方法会在Widget属性发生变化时调用,例如父Widget的属性发生变化时;
setState方法会在State对象的状态发生变化时调用,用于更新状态;

在销毁阶段中,Widget会触发一系列生命周期方法来响应不同的事件;
这些方法包括deactivate和dispose;
deactivate方法会在State对象暂时从视图树中移除时调用,例如当页面被覆盖时;
dispose方法会在永久从视图树中移除时调用,通常用于释放所有资源。

Widget的更新条件

setState()方法被调用、依赖的变量或数据发生变化、parent widget发生变化、Widget Tree重建等;
总的来说就是Flutter会递归遍历新旧Widget Tree的节点,对比它们的runtimeType和key属性是否相同,如果相同就会认为不需要更新。

Key

Key共分为LocalKey和GlobalKey,通过比较hashCode来判断两个Key是否相等,在使用中需要注意Key的唯一性;
GlobalKey是一个全局唯一的Key,可以在整个应用中引用;
LocalKey直接继承至Key,它应用于拥有相同父Element的Widget进行比较的情况;
LocalKey包括ValueKey(最常用的Key类型,它将一个值赋予给Key)、ObjectKey(与ValueKey类似,但是ObjectKey使用的是对象的引用)、UniqueKey(每次创建都会生成一个唯一的Key);
PageStorageKey继承自ValueKey,是用于存储用户滚动位置的专用key,以便应用可以保留当前的滚动位置,供后续使用。

二、Element、RenderObject、Paint

从Tree到渲染

对于一个StatefulWidget,当StatefulWidget被插入到Widget Tree中时,Flutter框架会调用其createElement()方法;
createElement()方法返回一个StatefulElement实例,StatefulElement随后被挂载到Element Tree上;

StatefulElement通过调用StatefulWidget的createState()方法来创建一个状态对象(State);
这个状态对象负责管理StatefulWidget的状态,并可以在状态变化时触发重建;

在适当的时机(如widget首次构建或状态变化时),Flutter框架会调用状态对象的build()方法;
build()方法返回一个Widget Tree,这个树描述了应该如何在屏幕上呈现该widget;
StatefulElement会将自身作为BuildContext传入到build()方法中,以便在Widget Tree中可以使用context相关的功能;

build()方法返回的Widget Tree最终会被转换为一系列的RenderObject;
每个widget都有一个对应的RenderObject类型,用于实际的布局和绘制工作;
这个转换过程是通过Widget Tree的深度优先遍历来完成的,每个widget都会调用其自己的createElement()和build()方法来参与这个过程;
最终,每个widget都会与一个或多个RenderObject关联起来,形成一个Render object Tree;

一旦Render object Tree被构建完成,Flutter就会开始布局和绘制过程;
布局过程确定每个render object的大小和位置;
绘制过程则使用Skia图形库(或其他平台特定的图形API)来将render object渲染到屏幕上。

总结

Widget定义了用户界面的结构和样式,是声明性的;
Element是Widget的实例化对象,负责维护UI的状态并与RenderObject进行协调;
RenderObject负责实际的布局和绘制工作,使用Paint对象来执行绘图操作;
Paint定义了绘图操作的样式和效果。