跟我学flutter:细细品Widget(四)Widget 渲染过程 与 RenderObjectWidget

12 篇文章 0 订阅

前言

StatelessWidget 和 StatefulWidget 只是用来组装控件的容器,并不负责组件最后的布局和绘制。在 Flutter 中,布局和绘制工作实际上是在 Widget 的另一个子类 RenderObjectWidget 内完成的。
RenderObjectWidget为RenderObjectElement提供配置信息。
RenderObjectElement包装了RenderObject,RenderObject为应用程序提供真正的渲染。

源码

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

  @override
  @factory
  RenderObjectElement createElement();

  @protected
  @factory
  RenderObject createRenderObject(BuildContext context);

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

  @protected
  void didUnmountRenderObject(covariant RenderObject renderObject) { }
}
  • createElement 需要返回一个继承RenderObjectElement的类
  • createRenderObject 创建 Render Widget 对应的 Render Object,同样子类需要重写该方法。该方法在对应的 Element 被挂载到树上时调用(Element.mount),即在 Element 挂载过程中同步构建了「Render Tree」
  • updateRenderObject 在 Widget 更新后,修改对应的 Render Object。该方法在首次 build 以及需要更新 Widget 时都会调用;
  • didUnmountRenderObject 「Render Object」从「Render Tree」上移除时调用该方法。

RenderObjectElement 源码

abstract class RenderObjectElement extends Element {
  RenderObject _renderObject;
 
  @override
  void mount(Element parent, dynamic newSlot) {
    super.mount(parent, newSlot);
    _renderObject = widget.createRenderObject(this);
    attachRenderObject(newSlot);
    _dirty = false;
  }
   
  @override
  void update(covariant RenderObjectWidget newWidget) {
    super.update(newWidget);
    widget.updateRenderObject(this, renderObject);
    _dirty = false;
  }
  ...
}
  • mount: RenderObject 对象的创建,以及与渲染树的插入工作,插入到渲染树后的 Element 就可以显示到屏幕中了。
  • update: 如果 Widget 的配置数据发生了改变,那么持有该 Widget 的 Element 节点也会被标记为 dirty。在下一个周期的绘制时,Flutter 就会触发 Element 树的更新,并使用最新的 Widget 数据更新自身以及关联的 RenderObject 对象,接下来便会进入 Layout 和 Paint 的流程。而真正的绘制和布局过程,则完全交由 RenderObject 完成。

RenderObject 主要处理一些固定的操作,如:布局、绘制和 Hit testing。 与ComponentElement一样RenderObjectElement也是抽象类,不同的是ComponentElement不会直接创建RenderObject,而是间接通过创建其他Element创建RenderObject。

RenderObjectElement主要有三个系统的子类,分别处理renderObject作为child时的不同情况。

  1. LeafRenderObjectElement:叶子渲染对象对应的元素,处理没有children的renderObject。
  2. SingleChildRenderObjectElement:处理只有单个child的renderObject。
  3. MultiChildRenderObjectElement: 处理有多个children的渲染对象

有时RenderObject的child模型更复杂一些,比如多维数组的形式,则可能需要基于RenderObjectElement实现一个新的子类。

RenderObjectElement 充当widget与renderObject之间的中介者。需要进行方法覆盖,以便它们返回元素期望的特定类型,例如:

class FooElement extends RenderObjectElement {                                       
                                                                                    
 @override                                                                          
 Foo get widget => super.widget; 
                                                   
@override                                                                          
RenderFoo get renderObject => super.renderObject;                                  
                                                                          
}               

widget返回Foo,renderObject 返回RenderFoo

系统常用组件与RenderObjectElement:

常用组件Widget(父级)Element
Flex/Wrap/Flow/StackMultiChildRenderObjectWidgetMultiChildRenderObjectElement
RawImage(Imaget)/ErrorWidgetLeafRenderObjectWidgetLeafRenderObjectElement
Offstage/SizedBox/Align/PaddingSingleChildRenderObjectWidgetSingleChildRenderObjectElement

RenderObject源码

abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin implements HitTestTarget {
  ...
  void layout(Constraints constraints, { bool parentUsesSize = false }) {...}
  
  void paint(PaintingContext context, Offset offset) { }
}

布局和绘制完成后,接下来的事情就交给 Skia 了。在 VSync 信号同步时直接从渲染树合成 Bitmap,然后提交给 GPU。

文章参考:https://www.jianshu.com/p/c3de443a70c7

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

二蛋和他的大花

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

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

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

打赏作者

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

抵扣说明:

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

余额充值