谈到Flutter的渲染,就离不开Widget、Element、RenderObject这三个概念。在Flutter中和大家接触最多的就是Widget,对于Widget很容易理解,可以看作是组件或控件的概念,那么Element和RenderObject是什么,他们具体干什么的,初学者就会有些难以理解。这篇文章就介绍一下Widget、Element和RenderObject这三个概念,并且说明他们是如何协同工作的。
首先我们来看一段简单Demo,这段代码包含两个Widget:
void main() => runApp(DemoWidget());
class DemoWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 0),
);
}
}
现在我们来看看Flutter是如何开始渲染的。我们相当于以这种声明的形式创建了一棵包含2个Widget(DemoWidget和Padding)的Widget树提供给了Flutter。当运行的时候,Flutter会创建一个RootWidget,把我们定义的Widget树加入其中,这样就生成了一棵完整的Widget树。Flutter有了这棵Widget树是不是就可以直接去渲染了呢,并不是这样的。

接下来,我们的Element就要闪亮登场了,RootWidget会通过调用著名的Widget.createElement创建一个RootElement,同时这个RootElement拥有了RootWidget也就拥有了整个Widget树。
// RenderObjectToWidgetAdapter类的部分源码
// RenderObjectToWidgetAdapter就是RootWidget。
// RenderObjectToWidgetElement就是RootElement。
class RenderObjectToWidgetAdapter<T extends RenderObject> extends RenderObjectWidget {
...
@override
RenderObjectToWidgetElement<T> createElement() => RenderObjectToWidgetElement<T>(this);
...
}
RootElement会递归遍历整个Widget树。通过调用每个Widget的createElement方法创建相应的Element,按Widget树的结构连接起来,就这样生成了Element树。

在RootElement遍历Widget树创建Element同时,Element也会调用Widget的createRenderObject创建RenderObject,同时也按树的结构连接起来,这样,Flutter又得到了第三棵树也就是RenderObject树。而RootRenderObject就是RootWidget的createRenderObject方法返回的RenderObject。
// Padding类的部分源码
// 通过createRenderObject获得RenderObject。
class Padding extends SingleChildRenderObjectWidget {
..
@override
RenderPadding createRenderObject(BuildContext context) {
return RenderPadding(
padding: padding,
textDirection: Directionality.of(context),
);
}
..
}
RenderObject实现了基础的layout和绘制协议,一些RenderObject子类则实现了子节点模型和定义坐标系统。实际上只有RenderObject树,参与了最后的渲染绘制。也就是不管是Widget树还是Element树最终的目的就是为了生成RenderObject树来进行渲染。
// RendererBinding类的部分源码
@protected
void drawFrame() {
...
// renderView 就是RootRenderObject
renderView.compositeFrame(); // 发送给GPU
谈到Flutter的渲染,就离不开Widget、Element、RenderObject这三个概念。在Flutter中和大家接触最多的就是Widget,对于Widget很容易理解,可以看作是组件或控件的概念,那么Element和RenderObject是什么,他们具体干什么的,初学者就会有些难以理解。这篇文章就介绍一下Widget、Element和RenderObject这三个概念,并且说明他们是如何协同工作的。
首先我们来看一段简单Demo,这段代码包含两个Widget:
void main() => runApp(DemoWidget());
class DemoWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 0),
);
}
}
现在我们来看看Flutter是如何开始渲染的。我们相当于以这种声明的形式创建了一棵包含2个Widget(DemoWidget和Padding)的Widget树提供给了Flutter。当运行的时候,Flutter会创建一个RootWidget,把我们定义的Widget树加入其中,这样就生成了一棵完整的Widget树。Flutter有了这棵Widget树是不是就可以直接去渲染了呢,并不是这样的。

接下来,我们的Element就要闪亮登场了,RootWidget会通过调用著名的Widget.createElement创建一个RootElement,同时这个RootElement拥有了RootWidget也就拥有了整个Widget树。
// RenderObjectToWidgetAdapter类的部分源码
// RenderObjectToWidgetAdapter就是RootWidget。
// RenderObjectToWidgetElement就是RootElement。
class RenderObjectToWidgetAdapter<T extends RenderObject> extends RenderObjectWidget {
...
@override
RenderObjectToWidgetElement<T> createElement() => RenderObjectToWidgetElement<T>(this);
...
}
RootElement会递归遍历整个Widget树。通过调用每个Widget的createElement方法创建相应的Element,按Widget树的结构连接起来,就这样生成了Element树。

在RootElement遍历Widget树创建Element同时,Element也会调用Widget的createRenderObject创建RenderObject,同时也按树的结构连接起来,这样,Flutter又得到了第三棵树也就是RenderObject树。而RootRenderObject就是RootWidget的createRenderObject方法返回的RenderObject。
// Padding类的部分源码
// 通过createRenderObject获得RenderObject。
class Padding extends SingleChildRenderObjectWidget {
..
@override
RenderPadding createRenderObject(BuildContext context) {
return RenderPadding(
padding: padding,
textDirection: Directionality.of(context),
);
}
..
}
RenderObject实现了基础的layout和绘制协议,一些RenderObject子类则实现了子节点模型和定义坐标系统。实际上只有RenderObject树,参与了最后的渲染绘制。也就是不管是Widget树还是Element树最终的目的就是为了生成RenderObject树来进行渲染。
// RendererBinding类的部分源码
@protected
void drawFrame() {
...
// renderView 就是RootRenderObject
renderView.compositeFrame(); // 发送给GPU
谈到Flutter的渲染,就离不开Widget、Element、RenderObject这三个概念。在Flutter中和大家接触最多的就是Widget,对于Widget很容易理解,可以看作是组件或控件的概念,那么Element和RenderObject是什么,他们具体干什么的,初学者就会有些难以理解。这篇文章就介绍一下Widget、Element和RenderObject这三个概念,并且说明他们是如何协同工作的。
首先我们来看一段简单Demo,这段代码包含两个Widget:
void main() => runApp(DemoWidget());
class DemoWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 0),
);
}
}
现在我们来看看Flutter是如何开始渲染的。我们相当于以这种声明的形式创建了一棵包含2个Widget(DemoWidget和Padding)的Widget树提供给了Flutter。当运行的时候,Flutter会创建一个RootWidget,把我们定义的Widget树加入其中,这样就生成了一棵完整的Widget树。Flutter有了这棵Widget树是不是就可以直接去渲染了呢,并不是这样的。

接下来,我们的Element就要闪亮登场了,RootWidget会通过调用著名的Widget.createElement创建一个RootElement,同时这个RootElement拥有了RootWidget也就拥有了整个Widget树。
// RenderObjectToWidgetAdapter类的部分源码
// RenderObjectToWidgetAdapter就是RootWidget。
// RenderObjectToWidgetElement就是RootElement。
class RenderObjectToWidgetAdapter<T extends RenderObject> extends RenderObjectWidget {
...
@override
RenderObjectToWidgetElement<T> createElement() => RenderObjectToWidgetElement<T>(this);
...
}
RootElement会递归遍历整个Widget树。通过调用每个Widget的createElement方法创建相应的Element,按Widget树的结构连接起来,就这样生成了Element树。

在RootElement遍历Widget树创建Element同时,Element也会调用Widget的createRenderObject创建RenderObject,同时也按树的结构连接起来,这样,Flutter又得到了第三棵树也就是RenderObject树。而RootRenderObject就是RootWidget的createRenderObject方法返回的RenderObject。
// Padding类的部分源码
// 通过createRenderObject获得RenderObject。
class Padding extends SingleChildRenderObjectWidget {
..
@override
RenderPadding createRenderObject(BuildContext context) {
return RenderPadding(
padding: padding,
textDirection: Directionality.of(context),
);
}
..
}
RenderObject实现了基础的layout和绘制协议,一些RenderObject子类则实现了子节点模型和定义坐标系统。实际上只有RenderObject树,参与了最后的渲染绘制。也就是不管是Widget树还是Element树最终的目的就是为了生成RenderObject树来进行渲染。
// RendererBinding类的部分源码
@protected
void drawFrame() {
...
// renderView 就是RootRenderObject
renderView.compositeFrame(); // 发送给GPU