Flutter —— 渲染原理

2,251 阅读4分钟

这是我参与11月更文挑战的第27天,活动详情查看:2021最后一次更文挑战

1. 渲染原理

在Flutter实战中写道,Flutter 框架的布局、绘制的处理流程是这样的:

  • 根据 Widget 树生成一个 Element 树,Element 树中的节点都继承自 Element 类。
  • 根据 Element 树生成 Render 树(渲染树),渲染树中的节点都继承自RenderObject 类。
  • 根据渲染树生成 Layer 树,然后上屏显示,Layer 树中的节点都继承自 Layer 类。 真正的布局和渲染逻辑在 Render 树中,Element 是 Widget 和 RenderObject 的粘合剂,可以理解为一个中间代理。

2. Render 树

不是所有的Widget 都会生成render,比如Container就不会创建RenderObject。

在这里插入图片描述

在这里插入图片描述

只有继承自RenderObject类的对象才会生成RenderObject对象,比如Column,这样就会被渲染引擎直接渲染。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在renderObject里面有两个重要的方法就是createElement 和 createRenderObject,这两个方法都是抽象方法,那么在子类中应该有相应的实现。

在这里插入图片描述

先来看createRenderObject方法,在flex中找到了createRenderObject的实现。createRenderObject里面只是做了一件事就是创建了RenderFlex

在这里插入图片描述

点进去看到RenderFlex继承自RenderBox。

在这里插入图片描述

在点进去看到RenderBox继承自RenderObject。

在这里插入图片描述

所以createRenderObject也就是返回了一个RenderObject对象。那么也就是说,并不是所有的Widget都会独立渲染,只有实现了createRenderObject并且返回了RenderObject对象的才会被独立渲染。

3. Element 树

所有的Widget都会创建一个Element对象。看到之前的createElement方法。

  RenderObjectElement createElement();

看一下子类是如何实现createElement方法的。这里在MultiChildRenderObjectWidget找到了方法的实现,这里返回了一个MultiChildRenderObjectElement对象。

在这里插入图片描述

MultiChildRenderObjectElement继承自RenderObjectElement。

在这里插入图片描述

接下来看StatelessWidget 里面是否有实现createElement方法。进去后发现是有的。

在这里插入图片描述

再来看一下StatefulWidget,也是有的。

在这里插入图片描述

而这里也可以看到,所有继承自Widget的,都有element。所以这里可以得知,Widget树和element树是一一对应的关系。

在这里插入图片描述

在StatefulWidget里面的createElement打下断点后运行。

在这里插入图片描述

这里第一个调用这个方法的是material app。

在这里插入图片描述

如果是StatelessWidget里面的createElement的话那么就应该是MyApp。

在这里插入图片描述

往下走一步之后来到了这里,看到有调用一个mount方法。

在这里插入图片描述

点进去之后看到注释,大概就是说当有一个新的element被添加的时候,mount方法都会被调用一次。也就是说当有一个新的Widget被创建的时候,mount方法都会被调用一次。

在这里插入图片描述

接下来看renderObject里面的mount方法。 在MultiChildRenderObjectWidget里面的createElement方法打下断点。

在这里插入图片描述

点击下一步发现也是有调用mount方法的。

在这里插入图片描述

而createRenderObject在mount方法之后也就是createElement方法之后。所以过程是Widget树 —— Element树 —— Render树

在这里插入图片描述

在createRenderObject下面一个函数mount里面就会调用createRenderObject创建RenderObject。

在这里插入图片描述

4. Element 和 Widget 的关系

StatelessWidget中createElement的是StatelessElement。

在这里插入图片描述

StatelessElement 继承自ComponentElement

在这里插入图片描述

来到ComponentElement,看到了这里有mount方法,在mount里面调用了_firstBuild方法。

在这里插入图片描述

_firstBuild里面则调用了rebuild。

在这里插入图片描述

rebuild里面也有一堆判断,然后调用了performRebuild方法。

在这里插入图片描述

看到performRebuild只是一个定义。

在这里插入图片描述

接下来去componentElement里面看performRebuild方法。看到这里有个built变量,并且等于build方法

在这里插入图片描述

看到build还是一个方法的定义。

在这里插入图片描述

看到StatelessElement里面的build方法直接返回widget的build方法的返回值,而这个widget就是StatelessWidget。

在这里插入图片描述

那么也就是说,当创建一个StatelessWidget对象的时候,就会

  • 调用createElement方法,
    • 创建componentElement对象,调用mount方法
  • 调用_firstBuild方法
  • 调用rebuild方法
  • 调用performRebuild方法
  • 调用了StatelessElement里面的build方法
  • 调用了StatelessWidget对象的build方法进行渲染

这里证明StatelessElement里面的widget是外面的StatelessWidget对象。 当这里调用createElement的时候,这里的this就是StatelessWidget对象。

在这里插入图片描述

而在StatelessElement时候,这里面的widget就是传进来的StatelessWidget对象,并且传给了super。

在这里插入图片描述

来到ComponentElement,又传给了ComponentElement的super。

在这里插入图片描述

然后看到Element里面接收到了这个widget,就赋值给了_widget。

在这里插入图片描述

  • Widget的渲染原理
    • 并不是所有的Widget都会被独立渲染!只有继承RenderObjectWidget的才会创建RenderObject对象!
    • 在Flutter渲染的流程中,有三颗重要的树!Flutter引擎是针对Render树进行渲染!
      • Widget树、Element树、Render树
        • 每一个Widget都会创建一个Element对象
          • 隐式调用createElement方法。Element加入Element树中,它会创建三种Element
          • RenderElement主要是创建RenderObject对象, 继承RenderObjectWidget的Widget会创建RenderElement
            • 创建RanderElement
            • Flutter会调用mount方法,调用createRanderObject方法
          • StatefulElement继承ComponentElement,StatefulWidget会创建StatefulElement
            • 调用createState方法,创建State
            • 将Widget赋值给state
            • 调用state的build方法 并且将自己(Element)传出去,build里面的context 就是Widget的Element !
          • StatelessElement继承ComponentElement,StatelessWidget会创建StatelessElement
            • 主要就是调用build方法 并且将自己(Element)传出去