I want to take a screenshot of a screen but I want to hide/blur/paint some Widgets in the resulting screenshot, but not in the app. Something like this:

The first picture is what I want to see in the app, no changes. The second picture is what I want to see in the screenshot, a specific widget painted.
My first thought was to calculate absolute coordinates of the specific widget, but in order to do this, I should add a GlobalKey to each of the widgets of the screen, and this is not feasible for my case.
How to do this without adding a GlobalKey to each of the widgets of the screen?
My current approach for taking a screenshot is:
final pixelRatio = MediaQuery.of(context).devicePixelRatio;
final boundary = boundaryKey.currentContext!.findRenderObject() as RenderRepaintBoundary;
final image = await boundary.toImage(pixelRatio: pixelRatio);
This is what I'm using to get coordinates of a Widget that has a GlobalKey:
extension GlobalKeyExtension on GlobalKey {
Rect? get globalPaintBounds {
final renderObject = currentContext?.findRenderObject();
var translation = renderObject?.getTransformTo(null).getTranslation();
if (translation != null) {
return renderObject!.paintBounds
.shift(Offset(translation.x, translation.y));
} else {
return null;
}
}
}
I think you need to declare:
bool _hideWidget = false;
Next you this value with all widgets that you want to hide while taking screenshot:
floatingActionButton: _hideWidget ? const SizedBox.shrink() : FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
In method that you use for taking screenshot, use next:
Future takeScreenShot() async {
final RenderRepaintBoundary boundary = previewContainer.currentContext!.findRenderObject()! as RenderRepaintBoundary;
if (boundary.debugNeedsPaint) {
print("Waiting for boundary to be painted.");
await Future.delayed(const Duration(milliseconds: 20));
return takeScreenShot();
}
setState(() {
_hideWidget = !_hideWidget;
});
await Future.delayed(const Duration(seconds: 1));
final ui.Image image = await boundary.toImage(pixelRatio: 5);
final directory = (await getApplicationDocumentsDirectory()).path;
final ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png);
final Uint8List pngBytes = byteData!.buffer.asUint8List();
File imgFile = File('$directory/screenshot.png');
print('$directory/screenshot.png');
imgFile.writeAsBytes(pngBytes);
await Future.delayed(const Duration(seconds: 1));
setState(() {
_hideWidget = !_hideWidget;
});
}
PS: in asynchronius methods you must use FutureDelayed for properly working of SetState
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With