likes
comments
collection
share

Flutter 入门 - Widget -- Element -- RenderObject

作者站长头像
站长
· 阅读数 6

Widget

为什么需要自己写 build 方法

  • 某些 widget 会生成 RenderObject
  • 每一个 Widget 都会生成 Element 实例
  • 生成 Element 实例的时候会调用 mount 方法
  • statfulWidget、statelessWidgetextentsComponentElement
  • ComponentElement: mount -> _firstBuild -> rebuild -> performRebuild -> build
  • RenderObjectElement: mount -> _widget.createRenderObject

Flutter 入门 - Widget -- Element -- RenderObject

组件Widget

statfulWidget、statelessWidgetextentsComponentElement 不会生成 RenderObject

  • Container
  • Text
  • 自己手写的 Widget

statfulWidget

如果是一个StatefulWidget,则创建出来的是一个StatefulElement

我们来看一下StatefulElement的构造器:

  • 调用widget的createState()
  • 所以StatefulElement对创建出来的State是有一个引用的
  • 而_state又对widget有一个引用
  StatefulElement(StatefulWidget widget)
      : _state = widget.createState(),
  ....省略代码
  _state._widget = widget;

而调用build的时候,本质上调用的是_state中的build方法:

Widget build() => state.build(this);

创建流程

ComponentElement: mount -> _firstBuild -> rebuild -> performRebuild -> build

非组件 Widget

Padding

  • 创建Element: RenderObjectElement
  • RenderObjectElement: mount -> _widget.createRenderObject
  • 渲染Widget: 生成RenderObject

Widget 继承链

Padding -> SingleChildRenderObjectWidget -> RenderObjectWidget -> Widget

Element 继承

RenderPadding -> RenderShiftedBox -> RenderBox -> RenderObject

Element

大量的 widget 被重复创建和销毁,属于不稳定的,那谁来维持整个程序的渲染稳定呢,Element! Element 是 Widget的实例,是在树中详细的位置

在每一次创建Widget的时候,会创建一个对应的Element,然后将该元素插入树中。

  • Element保存着对Widget的引用;

在SingleChildRenderObjectWidget中,我们可以找到如下代码:

  • 在Widget中,Element被创建,并且在创建时,将this(Widget)传入了;
  • Element就保存了对Widget的应用;
@override
  SingleChildRenderObjectElement createElement() => SingleChildRenderObjectElement(this);

在创建完一个Element之后,Framework会调用mount方法来将Element插入到树中具体的位置:

Flutter 入门 - Widget -- Element -- RenderObject

mount方法

在调用mount方法时,会同时使用Widget来创建RenderObject,并且保持对RenderObject的引用:

  • _renderObject = widget.createRenderObject(this);
@override
  void mount(Element parent, dynamic newSlot) {
    super.mount(parent, newSlot);
    _renderObject = widget.createRenderObject(this);
    assert(() {
      _debugUpdateRenderObjectOwner();
      returntrue;
    }());
    assert(_slot == newSlot);
    attachRenderObject(newSlot);
    _dirty = false;
  }

但是,如果你去看类似于Text这种组合类的Widget,它也会执行mount方法,但是mount方法中并没有调用createRenderObject这样的方法。

  • 我们发现ComponentElement最主要的目的是挂载之后,调用_firstBuild方法
@override
  void mount(Element parent, dynamic newSlot) {
    super.mount(parent, newSlot);
    assert(_child == null);
    assert(_active);
    _firstBuild();
    assert(_child != null);
  }

  void _firstBuild() {
    rebuild();
  }

RenderObject

创建过程小结

Widget只是描述了配置信息:

  • 其中包含createElement方法用于创建Element
  • 也包含createRenderObject,但是不是自己在调用

Element是真正保存树结构的对象:

  • 创建出来后会由framework调用mount方法;
  • 在mount方法中会调用widget的createRenderObject对象;
  • 并且Element对widget和RenderObject都有引用;

RenderObject是真正渲染的对象:

  • 其中有markNeedsLayout performLayout markNeedsPaint paint等方法

参考

Flutter的Widget-Element-RenderObject

转载自:https://juejin.cn/post/7000776333043171359
评论
请登录