likes
comments
collection
share

flutter渲染三棵树

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

背景

前几天我们在看ume源码的时候反复提到了renderObject,也简单提了一句renderObject是什么,今天就让我们好好看看flutter渲染的三棵树到底是什么

三棵树的关系(Widget、Element、RenderObject)

flutter渲染三棵树

看图说话,Widget是用来描述Element的,Element是Widget实例化出来的对象,通过Widget的createElement()方法生成出来的,而RenderObject是用于界面的布局和绘制的,保存了元素的大小,布局等信息,

举个不巧当的例子,Widget(产品经理),element(UI),renderObject(程序员),产品经理将我们的项目蓝图构建出来,描述给UI,UI将产品经理的想法,告诉程序员,程序员根据设计图开发程序,这就是简单的三棵树之间的关系

Widget

Flutter中几乎所有的对象都是Widget,而widget又分为StatelessWidgetStatefulWidget

  1. StatelessWidget:无中间状态的Widget,一旦创建便不可更改,只能再重新创建
  2. StatefulWidget:存在中间状态,同时引入了State来存放中间状态,通过调用state.setState()进行更新

State

通常一个StatefulWidget会对应一个State,State中有两个常用的属性Widgetcontext

Widget:与state相绑定的Widget实例 context:StatefulWidget所对应的BuildContext

abstract class State<T extends StatefulWidget> extends Diagnosticable {

  T get widget => _widget;
  T _widget;

  BuildContext get context => _element;
  StatefulElement _element;

  @protected
  @mustCallSuper
  void initState() { ... }

  @protected
  @mustCallSuper
  void reassemble() { ... }

  @protected
  void setState(VoidCallback fn) {
    // 省略掉一些逻辑判断
    final dynamic result = fn() as dynamic;
    _element.markNeedsBuild();
  }

  @protected
  @mustCallSuper
  void deactivate() { ... }

  @protected
  @mustCallSuper
  void dispose() { ... }

  @protected
  Widget build(BuildContext context);

  @protected
  @mustCallSuper
  void didChangeDependencies() { ... }
}

BuildContext

相信大家对BuildContext不会陌生,因为不管是StatelessWidget和StatefulWidget都会有个BuildContext,并且很多组件也需要我们传入BuildContext,那么BuildContext到底是什么,其实BuildContext就是Element的实例

Element

来看下Element的定义

abstract class Element extends DiagnosticableTree implements BuildContext {
  
  Element(Widget widget)
    : assert(widget != null),
      _widget = widget;

  Element _parent;

  @override
  Widget get widget => _widget;
  Widget _widget;

  RenderObject get renderObject { ... }

  @mustCallSuper
  void mount(Element parent, dynamic newSlot) { ... }

  @mustCallSuper
  void activate() { ... }

  @mustCallSuper
  void deactivate() { ... }

  @mustCallSuper
  void unmount() { ... }

以StatefulElement为例:

class StatefulElement extends ComponentElement {
  StatefulElement(StatefulWidget widget)
      : _state = widget.createState(),
        super(widget) {
    ...
    _state._element = this;
    _state._widget = widget;
    ...
  }

  State<StatefulWidget> get state => _state;
  State<StatefulWidget> _state;
  ...
  @override
  Widget build() => state.build(this);
  ...
}

创建实例时会将state已经赋值给_state,并将element及widget赋值给_state的_element以及_widget,从而使三者相关联起来

关于Element的生命周期我们留作明天再讲,先挖个坑

RenderObject

开篇提到RenderObject是负责渲染的,将所有的RenderObject组成一颗渲染树RenderTree,另外RenderObject的开销是很大的,所以Widget会进行节点的判断发生改变时才会重新创建RenderObject,

//framework.dart
 @protected
  Element updateChild(Element child, Widget newWidget, dynamic newSlot) {
    if (newWidget == null) {
      if (child != null)
        deactivateChild(child);
      return null;
    }
    Element newChild;
    if (child != null) {
      assert(() {
        final int oldElementClass = Element._debugConcreteSubtype(child);
        final int newWidgetClass = Widget._debugConcreteSubtype(newWidget);
        hasSameSuperclass = oldElementClass == newWidgetClass;
        return true;
      }());
      if (hasSameSuperclass && child.widget == newWidget) {
        if (child.slot != newSlot)
          updateSlotForChild(child, newSlot);
        newChild = child;
      } else if (hasSameSuperclass && Widget.canUpdate(child.widget, newWidget)) {
        if (child.slot != newSlot)
          updateSlotForChild(child, newSlot);
        child.update(newWidget);
        assert(child.widget == newWidget);
        assert(() {
          child.owner._debugElementWasRebuilt(child);
          return true;
        }());
        newChild = child;
      } else {
        deactivateChild(child);
        assert(child._parent == null);
        newChild = inflateWidget(newWidget, newSlot);
      }
    } else {
      newChild = inflateWidget(newWidget, newSlot);
    }

    assert(() {
      if (child != null)
        _debugRemoveGlobalKeyReservation(child);
      final Key key = newWidget?.key;
      if (key is GlobalKey) {
        key._debugReserveFor(this, newChild);
      }
      return true;
    }());

    return newChild;
  }
...
  static bool canUpdate(Widget oldWidget, Widget newWidget) {
    return oldWidget.runtimeType == newWidget.runtimeType
        && oldWidget.key == newWidget.key;
  }

结语

好了今天的源码查看就到这了, 作为Flutter届的一个小学生,希望大家多多指教,有问题的地方一起讨论

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