乐趣区

关于flutter:开发经验Flutter中对CustomScrollViewSliver组件截长图

问题

分享以后页面的需要,有时须要对页面进行截图。Flutter中截图个别应用 RepaintBoundary 搭配 GlobalKey 获取 Widget 的截图(PlatformView 无奈截图)。

然而当须要截图的指标是 CustomScrollView 时,尤其是应用了 SliverPersistentHeaderSliver组件时,不容易想出 RepaintBoundary 的嵌套地位,也就无奈获取长截图。

计划

百度根本查不到有用的信息,甚至还有一些离奇的计划:

下面长截图的现实状况是 SingleChildScrollView 这种容许咱们在 child 套一层 RepaintBoundary,但理论中也可能是 CustomScrollView 这种严格限度 children 类型的,此时咱们可能就须要借助相似 SliverToBoxAdapter 这种容器,并且在每个 child 上都套一个 RepaintBoundary

在每个 child 上都套一个 RepaintBoundary 显然是十分十分蹩脚的计划,在拍脑袋之前,咱们尽可能的多检索一些材料:

https://github.com/SachinGanesh/screenshot/issues/10#issuecomment-586302204

原文:

In your ListView that you wanna take a full screenshot, put a NeverScrollableScrollPhysics on it, then what is going to take control of the scrolling is the SingleChildScrollView.

意思就是给你的 CustomScrollView 一个 NeverScrollableScrollPhysics,而后扔到SingleChildScrollView 中进行截图。

很显然这个计划是更适合的,因为不须要关怀每一个 child,因为child 的数量可能尤其的多,难以去追踪 CustomScrollView 的每一个child

解决

组件:

GlobalKey paintKey = GlobalKey();
// 是否处在打印模式
bool printMode = false;

@override
Widget build(BuildContext context) {
// 页面
Widget body = CustomScrollView(physics: printMode ? NeverScrollableScrollPhysics() : null,
);
// 截图中
if (printMode) {
    body = AbsorbPointer(
        child: SingleChildScrollView(
        child: RepaintBoundary(
            key: paintKey,
            child: Container(
            color: ColorPlate.lightGray,
            child: body,
            ),
        ),
        ),
    ),
}
return body;
}

截图办法:

_share() async {setState(() {printMode = true;});
    await Future.delayed(Duration(milliseconds: 50));
    RenderRepaintBoundary boundary =
        paintKey.currentContext!.findRenderObject() as RenderRepaintBoundary;

    ui.Image image = await boundary.toImage(pixelRatio: 3);

    ByteData byteData = (await image.toByteData(format: ui.ImageByteFormat.png,))!;
    Uint8List pngBytes = byteData.buffer.asUint8List();

    print('截图胜利 ${pngBytes}')

    setState(() {printMode = false;});
  }
退出移动版