首页 > 解决方案 > 无法在颤动中截取屏幕截图

问题描述

包:flutter/src/rendering/proxy_box.dart':断言失败:第 2813 行 pos 12:'!debugNeedsPaint':不正确。

我试图在颤动中截取屏幕截图,但我遇到了异常。我访问了许多链接,但没有任何效果。

Future<Uint8List> _capturePng() async {
    try {
        print('inside');
        RenderRepaintBoundary boundary = _globalKey.currentContext.findRenderObject();
        ui.Image image = await boundary.toImage(pixelRatio: 3.0);
        ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png);
        var pngBytes = byteData.buffer.asUint8List();
        var bs64 = base64Encode(pngBytes);
        print(pngBytes);
        print(bs64);
        setState(() {});
        return pngBytes;
    } catch (e) {
        print(e);
    }
}

标签: flutter

解决方案


您可以在此处找到官方toImage示例。但看起来它在按钮点击和呼叫之间没有延迟就无法工作。toImage

官方仓库有问题:https ://github.com/flutter/flutter/issues/22308

造成这种情况的原因:您的点击初始化按钮的动画并被包括父母在内的递归调用,因此您应该再次RenderObject.markNeedsPaint等待。在这种情况下,函数只会抛出断言错误:debugNeedsPaintfalsetoImage

  Future<ui.Image> toImage({ double pixelRatio = 1.0 }) {
    assert(!debugNeedsPaint);
    final OffsetLayer offsetLayer = layer;
    return offsetLayer.toImage(Offset.zero & size, pixelRatio: pixelRatio);
  }

https://github.com/flutter/flutter/blob/f0553ba58e6455aa63fafcdca16100b81ff5c3ce/packages/flutter/lib/src/rendering/proxy_box.dart#L2857

  bool get debugNeedsPaint {
    bool result;
    assert(() {
      result = _needsPaint;
      return true;
    }());
    return result;
  }

https://github.com/flutter/flutter/blob/0ca5e71f281cd549f1b5284e339523ad93544c60/packages/flutter/lib/src/rendering/object.dart#L2011

实际上assert函数只在开发中使用,所以你可以看到你不会在生产中遇到错误的麻烦。但是我不知道您会遇到什么样的麻烦,可能没有)。

下一个代码不是很好,但它可以工作:

class _MyHomePageState extends State<MyHomePage> {
  GlobalKey globalKey = GlobalKey();

  Future<Uint8List> _capturePng() async {
    RenderRepaintBoundary boundary = globalKey.currentContext.findRenderObject();

    if (boundary.debugNeedsPaint) {
      print("Waiting for boundary to be painted.");
      await Future.delayed(const Duration(milliseconds: 20));
      return _capturePng();
    }

    var image = await boundary.toImage();
    var byteData = await image.toByteData(format: ImageByteFormat.png);
    return byteData.buffer.asUint8List();
  }

  void _printPngBytes() async {
    var pngBytes = await _capturePng();
    var bs64 = base64Encode(pngBytes);
    print(pngBytes);
    print(bs64);
  }

  @override
  Widget build(BuildContext context) {
    return RepaintBoundary(
      key: globalKey,
      child: Center(
        child: FlatButton(
          color: Color.fromARGB(255, 255, 255, 255),
          child: Text('Capture Png', textDirection: TextDirection.ltr),
          onPressed: _printPngBytes
        ),
      ),
    );
  }
}

推荐阅读