注册

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

前言

跟我学flutter系列:
跟我学flutter:我们来举个例子通俗易懂讲解dart 中的 mixin
跟我学flutter:我们来举个例子通俗易懂讲解异步(一)ioslate
跟我学flutter:我们来举个例子通俗易懂讲解异步(二)ioslate循环机制

跟我学flutter:在国内如何发布自己的Plugin 或者 Package

跟我学flutter:Flutter雷达图表(一)如何使用kg_charts

跟我学flutter:细细品Widget(一)Widget&Element初识

跟我学flutter:细细品Widget(二)StatelessWidget&StatefulWidget

跟我学flutter:细细品Widget(三)ProxyWidget,InheritedWidget

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

跟我学flutter:细细品Widget(五)Element

企业级篇目:
跟我学企业级flutter项目:用bloc手把手教你搭建用户认证系统
跟我学企业级flutter项目:dio网络框架增加公共请求参数&header
跟我学企业级flutter项目:如何用dio封装一套企业级可扩展高效的网络层
跟我学企业级flutter项目:如何封装一套易用,可扩展的Hybrid混合开发webview
跟我学企业级flutter项目:手把手教你制作一款低耦合空页面widget


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。


文章参考:http://www.jianshu.com/p/c3de443a7…

0 个评论

要回复文章请先登录注册