Flutter渲染机制:Widget、Elment和RenderObject

本文详细介绍了Flutter的渲染机制,包括Widget、Element和RenderObject的特性与关系。Widget用于描述UI配置,Element是树中特定位置的配置实例,RenderObject执行布局、绘制等操作。三者之间的关系体现在Widget创建Element,Element创建RenderObject,共同构建Flutter的UI。文章以Center和Text为例,展示了它们在三棵树中的位置关系。
摘要由CSDN通过智能技术生成

Widget、Elment和RenderObject


本文也发布于本人的知乎专栏:https://zhuanlan.zhihu.com/p/394568668

引子

Flutter源码阅读分析:Framework层的启动中,我们分析了Framework层的启动流程,其中讲到了在runApp方法中,调用到了attchRootWidget方法:

// ./packages/flutter/lib/src/widgets/binding.dart
void attachRootWidget(Widget rootWidget) {
   
  _readyToProduceFrames = true;
  _renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(
    container: renderView,
    debugShortDescription: '[root]',
    child: rootWidget,
  ).attachToRenderTree(buildOwner, renderViewElement as RenderObjectToWidgetElement<RenderBox>);
}

这个方法获取一个Widget并将其附到renderViewElement上,在必要的时候创建这个renderViewElement
其中涉及到了WidgetElementRender,都属于Flutter渲染机制。本文将对Flutter渲染机制进行分析。

首先看一下RenderObjectToWidgetAdapter这个类和其构造方法:

class RenderObjectToWidgetAdapter<T extends RenderObject> extends RenderObjectWidget {
   
  RenderObjectToWidgetAdapter({
   
    this.child,
    this.container,
    this.debugShortDescription,
  }) : super(key: GlobalObjectKey(container));
  ...
}

这个类的作用是桥接RenderObjectElement树,其中container就是RenderObject,而Element树则插入在其中。类型参数T是一种RenderObject,是container期望其孩子的类型。
再看一下RenderObjectToWidgetAdapter类的attachToRenderTree方法:

RenderObjectToWidgetElement<T> attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement<T> element ]) {
   
  if (element == null) {
   
    owner.lockState(() {
   
      element = createElement();
      assert(element != null);
      element.assignOwner(owner);
    });
    owner.buildScope(element, () {
   
      element.mount(null, null);
    });
    // This is most likely the first time the framework is ready to produce
    // a frame. Ensure that we are asked for one.
    SchedulerBinding.instance.ensureVisualUpdate();
  } else {
   
    element._newWidget = this;
    element.markNeedsBuild();
  }
  return element;
}

这个方法填充了widget,并且将结果RenderObject设置为container的孩子。如果element为空,那么则会创建一个新的element,否则的话,给定的element会调度一个更新,使得与当前widget关联。

从上面可以看出,对于Flutter框架来说,主要关注的就是WidgetElementRenderObject。下面我们来分析一下这三者的特点和关系。


Widget

在上文中的例子中,rootWidget是用户开发的Flutter应用的根节点,是一个Widget类。
Widget类的注释中,官方给出的定位是用于描述Element的配置。Widget是Flutter框架的中心类结构。一个Widget是UI中一个固定不变的部分。可以被填充成Element,而Element又管理底层的渲染树。
Widget本身是没有可变状态的,所有的成员变量都是final的。如果需要和一个Widget关联的可变状态,可以使用StatefulWidget,这个类会创建一个StatefulWidget,而它又会在填充成element和合并到树中的时候创建一个State对象。
一个给定的Widget可以被包含到树中0次或更多次。特别是Widget可以被多次放置到树中。每次Widget被放置到树中,都会填充成一个Element。看一下Widget基类的方法声明:

@immutable
abstract class Widget extends DiagnosticableTree {
   
  const Widget({
    this.key });

  final Key key;

  @protected
  Element createElement();

  ...

  static bool canUpdate(Widget oldWidget, Widget newWidget) {
   
    ...
  }

  static int _debugConcreteSubtype(Widget widget) {
   
    ...
  }
}

分别介绍一下这几个方法和成员变量。
首先是key这个成员变量,它用于控制在树中一个Widget如何替换另一个。主要有以下几种方式:更新Element、替换Element以及换位置。通常情况下,如果一个Widget是另一个的唯一孩子,那么不需要明确的key
createElement方法用于将配置填充为一个具体的实例。
canUpdate方法用于判断newWidget能否用于更新当前以oldWidget为配置的Element
_debugConcreteSubtype方法返回一个编码值,用于指示Widget的实际子类型,1表示StatefulWidget,2表示StatelessWidget
StatefullWidgetStatelessWidget都是Widget的抽象子类,下面看一下这两个子类的具体情况。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

董小虫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值