跟我学flutter:细细品Widget(一)Widget&Element初识

跟我学flutter:细细品Widget(一)Widget&Element初识,第1张

前言

Everything’s a widget!

Widget

Flutter 中 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

@immutable widget中的属性时不可变的,如果有可变的你需要放在state中。

如果属性发生变更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:

key

主要用于控制当 Widget 更新时,对应的 Element 如何处理 (是更新还是新建)。若某 Widget 是其「Parent Widget」唯一的子节点时,一般不用设置 key

LocalKey

LocalKey是diff算法的核心所在,用做Element和Widget的比较。常用子类有以下几个:

ValueKey:以一个数据为作为key,比如数字、字符等。
ObjectKey:以Object对象作为Key。
UniqueKey:可以保证key的唯一性,如果使用这个类型的key,那么Element对象将不会被复用。
PageStorageKey:用于存储页面滚动位置的key。

GlobalKey

每个globalkey都是一个在整个应用内唯一的key。globalkey相对而言是比较昂贵的,如果你并不需要globalkey的某些特性,那么可以考虑使用Key、ValueKey、ObjectKey或UniqueKey。
他有两个用途:

允许widget在应用程序中的任何位置更改其parent而不丢失其状态。应用场景:在两个不同的屏幕上显示相同的widget,并保持状态相同。可以获取对应Widget的state对象: createElement

一个 widget 可以对应多个Element

canUpdate

控制一个widget如何替换树中另一个widget。如果两个widget的runtimeType与key相同,则表示新的widget将替换旧的widget,并调用Element.update更新Element;否则旧的element将从树中移出,新的element插入树中。

Widget在重新build的时候,是增量更新的,而不是全部更新
runtimeType就是这个widget的类型

Widget类大家族

简述(后面文章将展开讲解):

StatelessWidget:无状态WidgetStatefulWidget:有状态Widget,值得注意的是StatefulWidget是不可变的,变化的状态在。ProxyWidget:其有2个比较重要的子类, ParentDataWidget和InheritedWidgetRenderObjectWidget:持有RenderObject对象的Widget,RenderObject是完成界面的布局、测量与绘制,像Padding,Table,Align都是它的子类

Widget的创建可以做到复用,通过const修饰,否则setState后,Widget重新被创建了(Element不会重建)

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种状态间的转换关系如下图所示:

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/993141.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存