Everything’s a widget!
WidgetFlutter 中 Widget是一个“描述一个UI元素的配置信息”,Widget就是接受元素,而不是真是绘制的显示元素。
类比原生的Android开发,Widget更像是负责UI配置的xml文件,而非负责绘制组件的View。 当一个Widget状态发生变化时,Widget就会重新调用build()函数来返回控件的描述,过程中Flutter框架会与之前的Widget进行比较,确保实现渲染树中最小的变动来保证性能和稳定性。换句话说,当Widget发生改变时,渲染树只会更新其中的一小部分而非全部重新渲染。
@immutable
abstract class Widget extends DiagnosticableTree {
const Widget({ this.key });
final Key? key;
@protected
@factory
Element createElement();
@override
String toStringShort() {
final String type = objectRuntimeType(this, 'Widget');
return key == null ? type : '$type-$key';
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense;
}
@override
@nonVirtual
bool operator ==(Object other) => super == other;
@override
@nonVirtual
int get hashCode => super.hashCode;
static bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType
&& oldWidget.key == newWidget.key;
}
...
}
图:
@immutable widget中的属性时不可变的,如果有可变的你需要放在state中。
key如果属性发生变更flutter则会重新构建Widget树,一旦 Widget 自己的属性变了自己就会被替换。
如你在开发过程中会有如下提示:This class (or a class that this class inherits from) is marked as ‘@immutable’, but one or more of its instance fields aren’t final:
主要用于控制当 Widget 更新时,对应的 Element 如何处理 (是更新还是新建)。若某 Widget 是其「Parent Widget」唯一的子节点时,一般不用设置 key
LocalKeyLocalKey是diff算法的核心所在,用做Element和Widget的比较。常用子类有以下几个:
ValueKey:以一个数据为作为key,比如数字、字符等。
ObjectKey:以Object对象作为Key。
UniqueKey:可以保证key的唯一性,如果使用这个类型的key,那么Element对象将不会被复用。
PageStorageKey:用于存储页面滚动位置的key。
每个globalkey都是一个在整个应用内唯一的key。globalkey相对而言是比较昂贵的,如果你并不需要globalkey的某些特性,那么可以考虑使用Key、ValueKey、ObjectKey或UniqueKey。
他有两个用途:
一个 widget 可以对应多个Element
canUpdate控制一个widget如何替换树中另一个widget。如果两个widget的runtimeType与key相同,则表示新的widget将替换旧的widget,并调用Element.update更新Element;否则旧的element将从树中移出,新的element插入树中。
Widget类大家族Widget在重新build的时候,是增量更新的,而不是全部更新
runtimeType就是这个widget的类型
简述(后面文章将展开讲解):
StatelessWidget:无状态WidgetStatefulWidget:有状态Widget,值得注意的是StatefulWidget是不可变的,变化的状态在。ProxyWidget:其有2个比较重要的子类, ParentDataWidget和InheritedWidgetRenderObjectWidget:持有RenderObject对象的Widget,RenderObject是完成界面的布局、测量与绘制,像Padding,Table,Align都是它的子类ElementWidget的创建可以做到复用,通过const修饰,否则setState后,Widget重新被创建了(Element不会重建)
通过Widget Tree,会生成一系列Element Tree,其主要功能如下:
维护这棵Element Tree,根据Widget Tree的变化来更新Element Tree,包括:节点的插入、更新、删除、移动等Element 是 Widget 和 RenderObject 的粘合剂,根据 Element 树生成 Render 树(渲染树) Element类大家族 两大类:简述(后面文章将展开讲解):
ComponentElement组合类Element。这类Element主要用来组合其他更基础的Element,得到功能更加复杂的Element。开发时常用到的StatelessWidget和StatefulWidget相对应的Element:StatelessElement和StatefulElement,即属于ComponentElement。
RenderObjectElement渲染类Element,对应Renderer Widget,是框架最核心的Element。RenderObjectElement主要包括LeafRenderObjectElement,SingleChildRenderObjectElement,和MultiChildRenderObjectElement。其中,LeafRenderObjectElement对应的Widget是LeafRenderObjectWidget,没有子节点;SingleChildRenderObjectElement对应的Widget是SingleChildRenderObjectWidget,有一个子节点;MultiChildRenderObjectElement对应的Widget是MultiChildRenderObjecWidget,有多个子节点。
Element生命周期Element有4种状态:initial,active,inactive,defunct。其对应的意义如下:
initial:初始状态,Element刚创建时就是该状态。active:激活状态。此时Element的Parent已经通过mount将该Element插入Element Tree的指定的插槽处(Slot),Element此时随时可能显示在屏幕上。inactive:未激活状态。当Widget Tree发生变化,Element对应的Widget发生变化,同时由于新旧Widget的Key或者的RunTimeType不匹配等原因导致该Element也被移除,因此该Element的状态变为未激活状态,被从屏幕上移除。并将该Element从Element Tree中移除,如果该Element有对应的RenderObject,还会将对应的RenderObject从Render Tree移除。但是,此Element还是有被复用的机会,例如通过GlobalKey进行复用。defunct:失效状态。如果一个处于未激活状态的Element在当前帧动画结束时还是未被复用,此时会调用该Element的unmount函数,将Element的状态改为defunct,并对其中的资源进行清理。 Element4种状态间的转换关系如下图所示:欢迎分享,转载请注明来源:内存溢出
评论列表(0条)