Flutter 三棵树的关系

Flutter 的 UI 系统有三棵树, 分别是:

  • Widget 树
  • Element 树
  • RenderObject 树

Widget

我们看看 Flutter 第一次创建的默认计数器项目:

void main() => runApp(new MyApp());   // *MyApp

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new MyHomePage(),         // *MyHomePage
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {/*...*/}
}

MyApp 是一个 StatelessWidget 类型的实例.

MyHomePage是一个 StatefulWidget 类型的实例.

StatelessWidgetStatefulWidget都是继承自 Widget 的抽象类.


我们知道 Widget 只是配置信息, 每次 build() 都会新建 widget. 构建 widget 是廉价的, 不会耗费多少资源,因为 Wiget 只是用来保存属性的容器.

StatelessWidgetStatefulWidget 中, 却找不到跟绘制属性有关的代码, 包括它们的父类里, 因为, 它两都是用于组装其他 Widget 的容器, 而存储绘制信息的, 在它两的最深层子 Widget 中.


Flutter 的 Widget 分为两种:

  • 组装其他 Widget 控件的容器 , 如 StatelessWidgetStatefulWidget
  • 描述绘制配置信息的 Widget, 如 RenderObjectWidget

包括系统控件和自定义控件, 都是上面三个之一的实现, 而 Widget 类是他们的祖父类, 提供公共的接口作为一层抽象, 不直接使用.

下面我们看看能影响绘制的 widget.

这个网站 列出了 Flutter 所有的 Widget, 在里面找到了继承 RenderObjectWidget 的 Widget:OpacityRow
Opacity 和 Row 都间接继承了 RenderObjectWidget 正如它们的父类也带有后缀名一样.

Opacity 描述了child widget 的透明度, Row 包含了描述了 children widgets 需要水平布局, 这些就属于绘制信息了.


通过查看 Flutter 的基本控件 Text 的源码可以发现, Text 继承了 StatelessWidget, 这就表示了 Text 是由其他控件组成的, 查看 Text 的 build 方法, 发现了 RichText, 而 RichText 继承了 MultiChildRender, 最底层的 widget 一定是 RenderObjectWidget, 从布局到具体控件, 一条下来这样, 逻辑就清晰了.

Flutter 的控件, 除了间接继承 RenderObjectWidget 类型的, 那么就一定可以在 build() 方法里找到一个间接继承 RenderObjectWidget 的控件.



Element

Widget 树是一棵对开发者来说的逻辑树, Element树才是真正存在于 Flutter 里的树.

在第一次创建 Widget 的时候,会对应创建一个 Element, 然后将该元素插入树中。如果之后 Widget 发生了变化,则将其与旧的 Widget 进行比较,并且相应地更新 Element。重要的是,Element 被不会重建,只是更新而已。

既然 Widget 有容器和带绘制信息的控件之分, 那么 Element 也是有的.

StatelessWidget 和 StatefulWidget 对应的 Element 继承自 ComponentElement, RenderObjectWidget 对应 RenderObjectElement.

/// An [Element] that uses a [StatelessWidget] as its configuration.
class StatelessElement extends ComponentElement {
  /// Creates an element that uses the given widget as its configuration.
  StatelessElement(StatelessWidget widget) : super(widget);
    
  @override
  StatelessWidget get widget => super.widget;
  // ...
}

/// An [Element] that uses a [StatefulWidget] as its configuration.
class StatefulElement extends ComponentElement {
  StatefulElement(StatefulWidget widget)
    : _state = widget.createState(), super(widget) {/*...*/}
    
  @override
  Widget build() => state.build(this);
    
  State<StatefulWidget> get state => _state;
    
  State<StatefulWidget> _state;
  // ...
}

/// An [Element] that uses a [SingleChildRenderObjectWidget] as its configuration.
/// ...
  SingleChildRenderObjectElement(SingleChildRenderObjectWidget widget) : super(widget);

  @override
  SingleChildRenderObjectWidget get widget => super.widget;
  // ...
}

Element 在 Widget 中创建.



RenderObject

RenderObjectWidget 保存了绘制属性, 而真正渲染的工作, 是在 RenderObject.

abstract class RenderObjectWidget extends Widget {
  
  const RenderObjectWidget({ Key key }) : super(key: key);

  @override
  RenderObjectElement createElement();

  @protected
  RenderObject createRenderObject(BuildContext context);

  @protected
  void updateRenderObject(BuildContext context, covariant RenderObject renderObject) { }

  @protected
  void didUnmountRenderObject(covariant RenderObject renderObject) { }
}

Element 通过 mount 方法插入到 Element Tree 中, RenderObject 的这时候创建.

~

参考资料: [译] Flutter,什么是 Widgets、RenderObjects 和 Elements?

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值