从Flutter源码分析Image是如何被渲染出来的

2,378 阅读2分钟

测试代码

下面是我们非常熟悉的代码,用来显示一张图片 结果如下

Image

要显示一个Image,需要经过加载图片资源,解码,上传显卡,渲染的过程,我们先抛开加载上传过程,看看图片是如何被渲染出来的 首先我们先看看我们常用的 Image widget 的实现

从上面看出,首先Image是一个我们熟悉的 StatefulWidget,那么他的逻辑应该在 build 里面,我们直接看build函数

在build内,简化不重要的代码后,逻辑也很简单,Image通过返回一个 RawImage Widget 对象实现渲染,那么我们继续研究RawImage的实现

RawImage

首先看到 RawImage 继承自 LeafRenderObjectWidget,LeafRenderObjectWidget又继承自RenderObjectWidget,这是一个单节点渲染Widget,通过 createRenderObjectupdateRenderObject 两个函数简化了Widget的渲染实现,下面找到该类的createRenderObject方法

可以看到在 createRenderObject 又创建了一个 RenderImage 渲染对象,再来看看RenderImage的实现

RenderImage

RenderImageRenderObject 的一种实现(三棵树的一种类型),其通过 performLayout 实现度量和布局,再通过 paint 方法进行绘制,现在看看其paint方法 paint内看到又调用了 paintImage 方法进行Image绘制,继续看paintImage的实现

paintImage

我对 paintImage 实现进行简化并增加了注释 通过这个代码可以看出,Image最终通过 canvas 接口进行渲染,其实是通过 canvas.drawImageRect 方法,形成绘图指令,最终传输到skia引擎进行绘制。同时通过 save,restore,clipRect,translate,scale 等canvas接口,处理图片镜像,裁剪及平铺的一些逻辑,至此图片就被渲染出来了。

canvas封装了

总结

现在整个绘制流程就很清晰了

Image Widget 通过 build 直接返回了一个 RawImage 对象,RawImage 通过 createRenderObject 方法创建了 RenderImage对象,RenderImage 通过 paint 调用了 paintImage 方法,paintImage 通过调用 canvasdrawImageRect 形成绘制指令,然后传输到 skia 引擎实现最终的绘制

后面我会对图片加载及gif图片渲染逻辑做进一步分析。