【 environment 】Flutter (Channel stable, 1.22.2, on Mac OS X 10.15.719H2, locale zh-hans-cn)

If you have ever encountered the need to save a Widget into a picture, let’s take a look at how this function is implemented. As you know, to write a new Widget, you need to inherit the StatelessWidget or StatefulWidget class, and then override the Build method, which passes in a BuildContext object. This should have something to do with the display of the Widget, so go into the source code and look at it

abstract class BuildContext
Copy the code

This is an abstract class, which you can find by looking at the source code

After the build process is complete, you can obtain the RenderObject, which will be used later.

The key way to

Future<Uint8List> widgetToImage(Widget widget) async { GlobalKey key = GlobalKey(); Completer = Completer<Uint8List>(); // 2. Completer setState(() {widgetToConvert = RepaintBoundary(key: key, child: widget); // 3. Display the widgets that need to be converted to images to get BuildContext}); WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { // 4. If (key.currentContext? .findRenderObject() ! = null) { RenderRepaintBoundary render = key.currentContext.findRenderObject(); ui.Image image = await render.toImage(); ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png); completer.complete(byteData.buffer.asUint8List()); } setState(() { widgetToConvert = null; // 5. The image has been drawn and the widget does not need to be displayed}); }); // 6. Return data. Use Completer to return the Future related to the callback data. }Copy the code

Page’s build method needs to be handled because the widget can only be converted to an image if it is displayed

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          child ?? Container(),
          Positioned.fill(
            child: yourPage(),
          ),
        ],
      ),
    );
  }
Copy the code

At this point, the basic conversion function is complete. However, if the Widget contains an image, you may find that the image is not displayed the first time the image is converted. This is because the drawing of the widget and the drawing of the image are not synchronized. So when the widget is drawn, the image is not loaded and therefore not displayed. The second time, because the image is already cached, the conversion is normal. So if you include images, you need to cache them manually first, using AssetImage as an example

AssetImage provider = AssetImage('assets/images/1.png');
await precacheImage(provider, context);
Copy the code

Full code address github.com/huangrrui/W…