package:flutter/src/rendering/proxy_box.dart': 失败的断言: line 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);
}
}
Run Code Online (Sandbox Code Playgroud)
exx*_*ain 18
您可以在此处找到官方toImage
示例。但看起来它在点击按钮和通话之间没有延迟。toImage
官方仓库有问题:https : //github.com/flutter/flutter/issues/22308
原因是:您的点击初始化按钮的动画RenderObject.markNeedsPaint
并被递归调用,包括父项,因此您应该等待一段debugNeedsPaint
时间false
。toImage
在这种情况下,函数只会抛出断言错误:
Future<ui.Image> toImage({ double pixelRatio = 1.0 }) {
assert(!debugNeedsPaint);
final OffsetLayer offsetLayer = layer;
return offsetLayer.toImage(Offset.zero & size, pixelRatio: pixelRatio);
}
Run Code Online (Sandbox Code Playgroud)
bool get debugNeedsPaint {
bool result;
assert(() {
result = _needsPaint;
return true;
}());
return result;
}
Run Code Online (Sandbox Code Playgroud)
实际上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
),
),
);
}
}
Run Code Online (Sandbox Code Playgroud)
您的代码已经很好,您在发布模式下应该不会遇到任何问题,因为来自docs:
debugNeedsPaint:此渲染对象的绘制信息是否脏。
这仅在调试模式下设置。一般来说,渲染对象不需要根据它们是否脏来调节它们的运行时行为,因为它们应该只在布局和绘制之前立即标记为脏。
它旨在供测试和断言使用。
debugNeedsPaint 为 false 且 debugNeedsLayout 为 true 是可能的(并且确实很常见)。在这种情况下,渲染对象仍将在下一帧中重新绘制,因为在绘制阶段之前,在布局渲染对象之后,框架会隐式调用 markNeedsPaint 方法。
但是,如果您仍然需要解决方案,则可以尝试以下操作:
Future<Uint8List> _capturePng() async {
try {
print('inside');
RenderRepaintBoundary boundary = _globalKey.currentContext.findRenderObject();
// if it needs repaint, we paint it.
if (boundary.debugNeedsPaint) {
Timer(Duration(seconds: 1), () => _capturePng());
return null;
}
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);
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3906 次 |
最近记录: |