在Flutter渲染过程中有三棵树:Widget树、Render树和Element树;
Widget树
什么是Widget树呢,其实在我们的Android Studio中能够直观的看到某一个页面渲染之后Widget树的样子,我们以聊天界面为例看一下页面的Widget树;
点击Android Studio右侧的Flutter Inspector工具,就可以呈现出当前页面的Widget树的层级关系:
需要注意的是,Flutter的渲染引擎并不是来直接渲染Widget树的,因为如果直接渲染Widget树,那么一旦build方法执行,那么整个Widget都需要重新渲染将会是非常消耗性能的(Widget是经常发生变化的);
Render树
除了Widget树,还有一个Render树,其实**Flutter**引擎渲染的是**RenderObject树**,它里边是一个个的RenderObject的对象;并非所有的Widget都会生成RenderObject,比如Container;只有最终继承自RenderObjectWidget的才会生成RenderObject,比如Column;
在RenderObjectWidget中有几个需要我们注意的地方,我们来看一下RenderObjectWidget的源码:
abstract class RenderObjectWidget extends Widget {const RenderObjectWidget({ Key? key }) : super(key: key);@override@factoryRenderObjectElement createElement();@protected@factoryRenderObject createRenderObject(BuildContext context);@protectedvoid updateRenderObject(BuildContext context, covariant RenderObject renderObject) { }@protectedvoid didUnmountRenderObject(covariant RenderObject renderObject) { }}
在RenderObjectWidget中有createElement()和createRenderObject()两个抽象方法;这两个方法需要RenderObjectWidget的子类来实现,我们可以通过Stack的继承关系来查看发现RenderObjectWidget的子类:
子类
MultiChildRenderObjectWidget中实现了createElement方法:@overrideMultiChildRenderObjectElement createElement() => MultiChildRenderObjectElement(this);
而
MultiChildRenderObjectElement继承自RenderObjectElement;子类
Stack中实现了createRenderObject方法:@overrideRenderStack createRenderObject(BuildContext context) {assert(_debugCheckHasDirectionality(context));return RenderStack(alignment: alignment,textDirection: textDirection ?? Directionality.maybeOf(context),fit: fit,clipBehavior: overflow == Overflow.visible ? Clip.none : clipBehavior,);}
在这个方法中创建了一个
RenderStack,而根据RenderStack的继承链发现其继承自RenderObject;
综上,继承自RenderObjectWidget的对象,既会创建Element树,又会创建RenderObject树;Element树
我们根据继承链可以发现
StatelessWidget直接继承自Widget,其内部没有RenderObject对象,但是有Element对象:
在Widget的源码中存在createElement()的抽象方法,也就是所有继承自Widget的对象都有Element对象:Widget树和Element树是一一对应的关系;
同样的,在StatefulWidget中实现了相同的方法:
我们在StatefulWidget中的createElement方法打上断点,然后使用Debug模式运行项目,查看一下断点的情况:
我们发现,从整个项目运行开始,第一个调用createElement的是MaterialApp这个组件;此时的this就是MaterialApp;
那么如果,我们将断点打在StatelessWidget中,我们来看一下执行的情况:
此时的this将会指向MyApp;我们的main.dart文件如下:
这个时候,我们单步执行一下:
这个时候代码将会执行到:
此处接下来将会执行mount方法,我们来看一下mount方法,我们主要看一下注释:
从注释我们可以得知,当有一个新的Element被添加到Element树的时候,mount方法将会被调用;因为Widget与Element是一一对应的,所以我们也可以理解为当有一个Widget被创建的时候,mount方法就会被调用;
新添加的
Element与原来的旧Element是有区别的;
我们从上文已经知道StatefulWidget和StatelessWidget是没有RenderObject对象的,那么我们继续查看一下有RenderObject对象的组件的mount方法:
单步断点执行:
接下来断点进入mount方法:
我们发现此时的mount方法调用了super.mount,我们进入super.mount方法:
我们发现在super.mount方法中调用了creatRenderObject方法,此时的mount方法是由RenderObjectElement实现的;
那么我们可以得出一下结论:
在
Flutter渲染流程中,最终是针对Render树中的对象进行渲染;当一个Widget被创建时,都会通过createElement方法创建一个Element加入到Element树中,然后会执行mount方法,此时如果含有RenderObject(Element是否继承自RenderObjectElement),则会在mount方法中通过createRenderObject方法创建RenderObject树,反之则不创建;
