flutter 将小部件保存到图像,而不会冻结抖动中的UI

bf1o4zei  于 2023-03-19  发布在  Flutter
关注(0)|答案(1)|浏览(131)

我有一个小部件,图像大小为2480x3508像素,图像中有一个动态QR码,我使用代码生成。当我使用RenderRepaintBoundary保存整个小部件(包括图像和QR码)并使用WebImageDownloader将其下载到设备时,UI冻结约30秒。
当我检查代码时,我发现我用.toByteData方法将dart ui.Image转换为Uint8List的部分是主要问题,它运行速度非常慢,我该如何解决这个问题?
我尝试使用compute函数,但它仍然冻结UI。

class EvoucherPage extends StatelessWidget {
  EvoucherPage({super.key});
  ...
  final GlobalKey genKeyA4 = GlobalKey();

  void download(voucherSize) async {
    ...
    if (voucherSize == "a4") {
      final RenderRepaintBoundary renderRepaintBoundary3 =
          genKeyA4.currentContext!.findRenderObject() as RenderRepaintBoundary;
      ui.Image image3 = await renderRepaintBoundary3.toImage();
      final byteData3 = await image3.toByteData(format: ui.ImageByteFormat.png);
      Uint8List data3 = byteData3!.buffer.asUint8List();
      await WebImageDownloader.downloadImageFromUInt8List(
        uInt8List: data3,
        imageQuality: 1,
        name: "voucher_a4",
      );
    }
    ...
  }

  @override
  Widget build(BuildContext context) {
    return ...
                      ElevatedButton.icon(
                        onPressed: () {
                          showDialog(
                            barrierDismissible: false,
                            context: context,
                            builder: (context) => const DownloadingDialog(),
                          );
                          Future.delayed(const Duration(milliseconds: 500), () {
                                 // Calling compute
                                 compute(download,controller.currentVoucherSize);
                              });
                            },
                            icon: const Icon(Icons.download),
                            label: const Text("Tải xuống"),
                          ),
                        ],
                      ),
                ...
                      child: SingleChildScrollView(
                                scrollDirection: Axis.horizontal,
                                child: RepaintBoundary(
                                  key: genKeyA4, // Key using here
                                  child: VoucherWidgetA4Download(),
                                ),
                              ),

我的小部件是无状态小部件,我尝试在小部件构建完成后通过运行代码从小部件获取字节数据来预缓存图像,但它不起作用,因为当我从服务器获取某些数据以生成QR代码时,我使用消费者刷新我的小部件,我不知道如何从控制器调用函数来预缓存小部件中的字节数据,如果我知道,它仍然冻结UI。
此时,我只是显示一个对话框,显示图像正在下载,并防止用户使用barrierdisdissociated =true进行任何操作,并将图像大小更改为1414x2000,以便更快地转换为字节数据,但放大时的图像质量不像原始图像。

q7solyqu

q7solyqu1#

试试这边

Future<void> _heavyTaskHandler() async {
    await compute(download, controller.currentVoucherSize);
  }
.....
   ElevatedButton.icon(
        onPressed: ()async {
          await showDialog(
            barrierDismissible: false,
            context: context,
            builder: (context) => const DownloadingDialog(),
          );
            // Calling compute
            await  _heavyTaskHandler();//pass data if needed 
          debugPrint("task end");
          },

相关问题