Flutter 绘制原理

Flutter中和绘制相关的对象有三个,分别是Canvas、Layer 和 Scene:

  • Canvas:封装了Flutter Skia各种绘制指令,比如画线、画圆、画矩形等指令。
  • Layer:分为容器类和绘制类两种;暂时可以理解为是绘制产物的载体,比如调用 Canvas 的绘制 API 后,相应的绘制产物被保存在 PictureLayer.picture 对象中。
  • Scene:屏幕上将要要显示的元素。在上屏前,我们需要将Layer中保存的绘制产物关联到 Scene 上。

Flutter 绘制流程:

  1. 构建一个 Canvas,用于绘制;同时还需要创建一个绘制指令记录器,因为绘制指令最终是要传递给 Skia 的,而 Canvas 可能会连续发起多条绘制指令,指令记录器用于收集 Canvas 在一段时间内所有的绘制指令,因此Canvas 构造函数第一个参数必须传递一个 PictureRecorder 实例。
  2. Canvas 绘制完成后,通过 PictureRecorder 获取绘制产物,然后将其保存在 Layer 中。
  3. 构建 Scene 对象,将 layer 的绘制产物和 Scene 关联起来。
  4. 上屏;调用window.render API 将Scene上的绘制产物发送给GPU。

Picture

  1. Picture 实际上是一系列的图形绘制操作指令,这一点可以参考 Picture 类源码的注释。
  2. Picture 要显示在屏幕上,必然会经过光栅化,随后Flutter会将光栅化后的位图信息缓存起来,也就是说同一个 Picture 对象,其绘制指令只会执行一次,执行完成后绘制的位图就会被缓存起来。

综合以上两点,我们可以看到 PictureLayer 的"绘制产物"一开始是一些列"绘图指令",当第一次绘制完成后,位图信息就会被缓存,绘制指令也就不会再被执行了,所以这时"绘制产物"就是位图了。为了便于理解,后续我们可以认为指的就是绘制好的位图。

Canvas绘制的位图转图片

既然 Picture 中保存的是绘制产物,那么它也应该能提供一个方法能将绘制产物导出,实际上,Picture有一个toImage方法,可以根据指定的大小导出Image。

复制代码
//将图片导出为Uint8List
final Image image = await pictureLayer.picture.toImage();
final ByteData? byteData = await image.toByteData(format: ImageByteFormat.png);
final Uint8List pngBytes = byteData!.buffer.asUint8List();
print(pngBytes);

Layer

作用

  1. 可以在不同的frame之间复用绘制产物(如果没有发生变化)。
  2. 划分绘制边界,缩小重绘范围。

类型

  1. OffsetLayer:根 Layer,它继承自ContainerLayer,而ContainerLayer继承自 Layer 类,我们将直接继承自ContainerLayer 类的 Layer 称为容器类Layer ,容器类 Layer 可以添加任意多个子Layer。
    1. 将组件树的绘制结构组成一棵树。

      因为 Flutter 中的 Widget 是树状结构,那么相应的 RenderObject 对应的绘制结构也应该是树状结构,Flutter 会根据一些"特定的规则"(后面解释)为组件树生成一棵 Layer 树,而容器类Layer就可以组成树状结构(父 Layer 可以包含任意多个子 Layer,子Layer又可以包含任意多个子Layer)。

    2. 可以对多个 layer 整体应用一些变换效果。

      容器类 Layer 可以对其子 Layer 整体做一些变换效果,比如剪裁效果(ClipRectLayer、ClipRRectLayer、ClipPathLayer)、过滤效果(ColorFilterLayer、ImageFilterLayer)、矩阵变换(TransformLayer)、透明变换(OpacityLayer)等。

  2. PictureLayer:保存绘制产物的 Layer,它直接继承自 Layer 类。我们将可以直接承载(或关联)绘制结果的 Layer 称为绘制类 Layer
相关推荐
审小匠OpenCPAi4 小时前
银行流水核查怎么自动化?单边匹配、双向勾稽与图聚类异常检测的工程对比
java·前端·人工智能·python·审计
Revolution614 小时前
一个公共表格组件,是怎么一步步失控的
前端·前端工程化
腻害兔5 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:CRM 客户关系模块深度解析——从线索到回款,一套完整的 B2B 销售闭环是怎么搭的?
java·前端·javascript·vue.js·产品经理·ai编程
whyfail5 小时前
前端学 Spring Boot(2):一次点击,如何穿过整个后端?
前端·spring boot·后端
AI多Agent协作实战派5 小时前
AI多Agent协作系统实战(二十三):Agent读HEARTBEAT.md不读AGENTS.md——openclaw的文件加载之谜
前端·数据库·人工智能·uni-app
2601_955760076 小时前
如何用 Claude Opus 5 API 批量扩展长尾关键词和文章选题
前端·python·搜索引擎
KaMeidebaby6 小时前
卡梅德生物技术快报|bli亲和力检测gst:告别批量跑胶:BLI实时酶切监测技术加速GST融合蛋白下游流程优化
前端·网络·数据库·人工智能·算法
触底反弹7 小时前
🚀 删了数据刷新又回来?3 组件 × 4 回调 × 3 坑讲透 React 父子通信
前端·javascript·react.js
耳东小鹿8 小时前
对象常用方法
前端
GitLqr8 小时前
Flutter 3.44 性能飞跃:深度解析 Android Platform View 的 HCPP 新特性
android·flutter·性能优化