Is it possible to build and render a widget off-stage, so not visible, and then capture the widget using a RepaintBoundary to save it as a image file?
Background: I want to capture a widget which is already build, but cant make it work with wrapping it with a RepaintBoundary as i cant supply a GlobalKey at this point. See Flutter - RepaintBoundary causes state reset of StatefulWidget
Therefore maybe a different approach is to just rebuild the widget off-stage at the time a capture is issued by the user, this time with a RepaintBoundary and a GlobalKey, and then throw the offstage rendered widget away.
I know there is a Offstage
widget but i am not sure on how to use it for this purpose. My current code gives me a failed assertion:
Failed assertion: line 2752 pos 12: '!debugNeedsPaint': is not true.
This is probably due to that Offstage
is not painted as the doc says:
A widget that lays the child out as if it was in the tree, but without painting anything...
Is there another way to achieve this?
Code:
The widget to capture is child
, the following build method is the method returning child
wrapped with a GestureDetector
which implements the capturing, there i packed in the Offstage
widget to capture.
@override
Widget build(BuildContext context) {
Widget child = Card(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: children,
),
);
return GestureDetector(
onLongPress: () async {
await showModalBottomSheet(context: context,
builder: (BuildContext bcontext) {
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Offstage(
offstage: true,
child: RepaintBoundary(
key: globalKey,
child: child,
),
),
ListTile(
title: 'Capture Widget,
onTap: () async {
Map<PermissionGroup, PermissionStatus> permissions = await PermissionHandler().requestPermissions([PermissionGroup.storage]);
if (permissions[PermissionGroup.storage] == PermissionStatus.granted) {
Directory externalDirectory = await getExternalStorageDirectory();
RenderRepaintBoundary boundary = globalKey.currentContext.findRenderObject();
final image = await boundary.toImage(pixelRatio: 2.0);
final byteData = await image.toByteData(format: ImageByteFormat.png);
String path = externalDirectory.path + '/' + uuid + '.png';
File(path).writeAsBytes(byteData.buffer.asUint8List());
}
Navigator.pop(context);
}
),
ListTile(
title: 'Cancel',
onTap: () {
Navigator.pop(context);
},
),
],
);
});
},
child: child,
);
}