三、Flutter的渲染機(jī)制之RenderObjectWidget、RenderObjectElement、RenderObject

RenderObjectWidgetWidget例如SizeBox,Column

RenderObjectElement是這類Widget生成的Element類型,
例如SizeBox對應(yīng)SingleChildRenderObjectElement(單子節(jié)點(diǎn)的Element

RenderObject才是真正負(fù)責(zé)繪制的對象,其中包含了paintlayout等方法~

Text組件為例:
class Text extends StatelessWidget
Textbuild返回的是
class RichText extends MultiChildRenderObjectWidget

MultiChildRenderObjectWidget - > MultiChildRenderObjectElement

abstract class MultiChildRenderObjectWidget extends RenderObjectWidget {
    MultiChildRenderObjectElement createElement() => MultiChildRenderObjectElement(this);
創(chuàng)建關(guān)系:
abstract class RenderObjectWidget extends Widget
  @override
  @factory
  RenderObjectElement createElement();

  @protected
  @factory
  RenderObject createRenderObject(BuildContext context);

RenderObjectElement會重寫mount

abstract class RenderObjectElement extends Element
...
  void mount(Element? parent, Object? newSlot) {
    super.mount(parent, newSlot);
    _renderObject = widget.createRenderObject(this);
    attachRenderObject(newSlot);
    _dirty = false;
  }
  void attachRenderObject(Object? newSlot) {

    _slot = newSlot;

    //查找上一個RenderObjectElement
    _ancestorRenderObjectElement = _findAncestorRenderObjectElement();

    //上一個RenderObjectElement插入當(dāng)前的renderObject
    _ancestorRenderObjectElement?.insertRenderObjectChild(renderObject, newSlot);
...

遍歷_parent(就是上個節(jié)點(diǎn)的element,這個_parent在每次的mount方法設(shè)置),一直遍歷知道找到最近的一個RenderObjectElement

  RenderObjectElement? _findAncestorRenderObjectElement() {
    Element? ancestor = _parent;
    while (ancestor != null && ancestor is! RenderObjectElement)
      ancestor = ancestor._parent;
    return ancestor as RenderObjectElement?;
  }

在回顧下inflateWidget

  Element inflateWidget(Widget newWidget, Object? newSlot) {
    //this為A newWidget則是B,通過Bwidget 創(chuàng)建對應(yīng)的element
    final Element newChild = newWidget.createElement();
    //新生成的element插入element樹中
    newChild.mount(this, newSlot);
    return newChild;
  }

SingleChildRenderObjectElement

  @override
  void insertRenderObjectChild(RenderObject child, Object? slot) {
    renderObject = this.renderObject;
    renderObject.child = child;
  }

MultiChildRenderObjectElement

  void insertRenderObjectChild(RenderObject child, IndexedSlot<Element?> slot) {
    renderObject = this.renderObject;
    renderObject.insert(child, after: slot.value?.renderObject);
  }

總結(jié):

inflateWidget會觸發(fā)RenderObjectWidgetcreateElement創(chuàng)建RenderObjectElement,
再調(diào)用RenderObjectElementmount方法
mount方法調(diào)用RenderObjectWidgetcreateRenderObject方法創(chuàng)建RenderObject
然后找到最近的一個父RenderObjectElement調(diào)用insertRenderObjectChild插入RenderObject

(注意:這里不是RenderObjectElementchild,而是RenderObjectElement關(guān)聯(lián)的RenderObjectchild, element樹里面都是element, RenderObject樹里面都是RenderObject)

MultiChildRenderObjectElement多子節(jié)點(diǎn)掛載邏輯

  void insertRenderObjectChild(RenderObject child, IndexedSlot<Element?> slot) {
    renderObject = this.renderObject;
    renderObject.insert(child, after: slot.value?.renderObject);
  }
  void insert(ChildType child, { ChildType? after }) {
    adoptChild(child);
    _insertIntoChildList(child, after: after);
  }

多節(jié)點(diǎn)添加子節(jié)點(diǎn)邏輯
每個子節(jié)點(diǎn)的parentDataafter用來指向前一個子節(jié)點(diǎn) previous指向下一個子節(jié)點(diǎn)

  • Father有子節(jié)點(diǎn)s1 s2 s3
    s2parentDataprevious會用來指向s1,s1next會指向s2
    以此類推
void _insertIntoChildList(ChildType child, { ChildType? after }) {
    final ParentDataType childParentData = child.parentData! as ParentDataType;
    //表示新增一個子節(jié)點(diǎn)
    _childCount += 1;
    //after == null表示這是多節(jié)點(diǎn)的第一個子節(jié)點(diǎn)
    if (after == null) {
      // insert at the start (_firstChild)
      childParentData.nextSibling = _firstChild;
      if (_firstChild != null) {
        final ParentDataType _firstChildParentData = _firstChild!.parentData! as ParentDataType;
        _firstChildParentData.previousSibling = child;
      }
      //傳入的child作為第一個子節(jié)點(diǎn)
      _firstChild = child;
      //如果_lastChild為空 則將child設(shè)置為_lastChild
      _lastChild ??= child;
    } else {
      final ParentDataType afterParentData = after.parentData! as ParentDataType;

      //這里通過雙向鏈表的結(jié)構(gòu)關(guān)聯(lián)器多個子節(jié)點(diǎn)

      //前子節(jié)點(diǎn)的尾部指向?yàn)榭?      if (afterParentData.nextSibling == null) {
        // insert at the end (_lastChild); we'll end up with two or more children
        //傳入的子節(jié)點(diǎn)的頭部指向前一個子節(jié)點(diǎn)
        childParentData.previousSibling = after;
        //前子節(jié)點(diǎn)的尾部指向當(dāng)前傳入的child
        afterParentData.nextSibling = child;

        _lastChild = child;
      } else {
        //在一個完整的雙向鏈表直接插入一個新的子節(jié)點(diǎn)
        //新的子節(jié)點(diǎn)自然頭部指向到前一個子節(jié)點(diǎn),尾部指向就是前一個子節(jié)點(diǎn)的指向
        childParentData.nextSibling = afterParentData.nextSibling;
        childParentData.previousSibling = after;

        final ParentDataType childPreviousSiblingParentData = childParentData.previousSibling!.parentData! as ParentDataType;
        final ParentDataType childNextSiblingParentData = childParentData.nextSibling!.parentData! as ParentDataType;
        //新的子節(jié)點(diǎn)的前一個子節(jié)點(diǎn)的next要指向新的子節(jié)點(diǎn)
        //afterParentData.nextSibling = child
        childPreviousSiblingParentData.nextSibling = child;
        //新的子節(jié)點(diǎn)的后面的一個子節(jié)點(diǎn)的previous也要指向新的子節(jié)點(diǎn)
        //nextParentData.previousSibling = child
        childNextSiblingParentData.previousSibling = child;
      }
    }
  }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容