Flutter 离屏渲染
最近看了一下 Flutter 里离屏渲染和组件截图相关的东西,先记录一下思路。这个需求一般会出现在生成分享图、把某个 widget 转成图片、或者需要在界面外提前渲染内容的时候。
RepaintBoundary
Flutter 里最常见的截图方式是给目标 widget 外面包一层 RepaintBoundary,再通过 GlobalKey 拿到 RenderRepaintBoundary。
大概流程是:
1 | final boundary = key.currentContext?.findRenderObject() |
这样可以把当前已经渲染出来的 widget 转成图片。
渲染时机
比较容易踩坑的是:widget 必须已经完成布局和绘制,才能截图。
如果刚创建完就立刻调用 toImage(),可能会拿不到 context,或者图片是空的。一般要等一帧:
1 | WidgetsBinding.instance.addPostFrameCallback((_) { |
如果内容里有网络图片,也要注意图片是否加载完成,否则截图出来可能是占位图。
真正的离屏
如果这个 widget 不在当前页面上,只是想在后台生成一张图,就麻烦一点。因为 Flutter 的 widget 需要经过 build、layout、paint 这一整套流程,不能只 new 一个 widget 就直接转图片。
常见做法是:
- 放在页面里但不可见的位置,等渲染完成后截图。
- 使用
Overlay临时插入,截图后移除。 - 自己搭一套离屏渲染 pipeline,但这个成本比较高,一般业务没必要。
前两种更适合业务场景,简单很多。
小结
目前我的理解是:
RepaintBoundary.toImage()适合截取已经渲染出来的 widget。- 截图前要等布局和绘制完成。
- 网络图片、字体、异步数据都会影响最终截图。
- 真正离屏渲染成本比较高,业务里优先考虑 Overlay 或隐藏节点方案。
这块后面如果要做分享图生成,可以再整理一版完整实现。