Flutter taking screen shot of widget without showing on screen

Viewed 918

I need to take screenshot of widget but didn't want to show the widget on screen.

I am doing this right now

My widget

      showSc ? Screenshot(
        controller: screenshotController,

        child: Container(
          color: Color(0xffE5E7E9),
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text('Payment Reminder', style: TextStyle(
                    fontFamily: 'PoppinsRegular',
                    fontSize: 19,
                    color: Color(0xff8f9ba8))),
                Text(Ggive.toString(), style: TextStyle(
                    fontFamily: 'PoppinsBold',
                    fontSize: 17,
                    color: Colors.red)),
                SizedBox(height: 20,),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Column(
                      children: [
                        Text(widget.data['selererName'].toString(), style: TextStyle(
                            fontFamily: 'PoppinsBold',
                            fontSize: 15,
                            color: Color(0xff8f9ba8))),

                      ],
                    ),
                    Image.asset('images/splash-logo.png', width: 120,)
                  ],
                )
              ],
            ),
          ),
        ),
      ) : Container(),

Capture

            GestureDetector(
              onTap: () async {

                print('click');
                _imageFile = null;
                screenshotController
                    .capture()
                    .then((Uint8List image) async {

                  _imageFile = image;
                  print(base64Encode(_imageFile));

                  FlutterShareMe()
                      .shareToWhatsApp(base64Image: 'data:image/jpeg;base64,${base64Encode(_imageFile)}', msg: 'Apna ${widget.data['selererName']} ko ${Ggive.toString()} Rupees dene hein');

                }).catchError((onError) {
                  print(onError);
                });


              },
              child: Column(
                children: [
                  Icon(Icons.messenger_outline_outlined),
                  Text(
                    'Whatsapp',
                    style: TextStyle(fontFamily: 'PoppinsRegular'),
                  )
                ],
              ),
            ),

But when i take screenshot and send to WhatsApp its not sending and if make showSc bool true then its working fine but i don't want to show this widget any one can give solution for this i am stuck here -_-

3 Answers

The way you built your screen doesn't make your widget invisible but rather inexistant.

Because of your boolean, the controller is not set and your page only contains an empty Container. That is why Screenshot cannot save anything at this point.

What you can do in your case is displaying your widget but creating an overlay on top of it in order to make it invisible but existant. The best widget to do that would be a Stack.

The stack is a LIFO so the last child will be on the top.

Try wrapping your Screenshot widget with a Stack :

Stack(
   children: [
      Screenshot(
        controller: screenshotController,
        ...
      ),
      Positioned.fill(
        child: Container(color: Colors.white)),
   ],
)

It is lacking a bit of context to provide the correct widget to put on top in terms of size / contraints, but feel free to adapt the Positioned as you see fit.

Why you wouldn't use repaint boundaries.

Create global key.

  GlobalKey frontScreenSnap = new GlobalKey();




     RepaintBoundary(
                          key: ScreenSnap,
                          child: Container(
          color: Color(0xffE5E7E9),
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text('Payment Reminder', style: TextStyle(
                    fontFamily: 'PoppinsRegular',
                    fontSize: 19,
                    color: Color(0xff8f9ba8))),
                Text(Ggive.toString(), style: TextStyle(
                    fontFamily: 'PoppinsBold',
                    fontSize: 17,
                    color: Colors.red)),
                SizedBox(height: 20,),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Column(
                      children: [
                        Text(widget.data['selererName'].toString(), style: TextStyle(
                            fontFamily: 'PoppinsBold',
                            fontSize: 15,
                            color: Color(0xff8f9ba8))),

                      ],
                    ),
                    Image.asset('images/splash-logo.png', width: 120,)
                  ],
                )
              ],
            ),
          ), 

),




Future<ByteData>  screenshot()async{

               RenderRepaintBoundary boundary =
    key.currentContext!.findRenderObject() as RenderRepaintBoundary;
    var image = await boundary.toImage(pixelRatio: 2);
    ByteData byteData = (await image.toByteData(format: ImageByteFormat.png))!;

  
    return byteData;
}

You can use this function anywhere i.e you can save the byteadata also you can assign it Image. inside

var data=screen();

Image(data.buffer.asUint8List());

if you want to screenshot widget not in screen, try this davinci:

import 'package:davinci/davinci.dart';
import 'package:davinci/core/davinci_capture.dart';
import 'package:flutter/material.dart';

class App extends StatefulWidget {
  @override
  _AppState createState() => _AppState();
}

class _AppState extends State<App> {
  ///1.create a globalkey variable
  GlobalKey imageKey;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.blueGrey,
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ///2. wrap the desired widget with Davinci widget
            Davinci(
              builder: (key) {
                ///3. set the widget key to the globalkey
                imageKey = key;
                return Container(
                  height: 150,
                  width: double.infinity,
                  color: Colors.black,
                  child: Padding(
                    padding: const EdgeInsets.all(18.0),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Container(
                          height: 50,
                          width: 50,
                          color: Colors.red,
                        ),
                      ],
                    ),
                  ),
                );
              },
            ),
            Padding(
              padding: const EdgeInsets.all(38.0),
              child: TextButton(
                onPressed: () async {
                  ///4. pass the globalKey varible to DavinciCapture.click.
                  await DavinciCapture.click(imageKey);
                },
                child: Text('capture',
                    style: TextStyle(
                      color: Colors.white,
                    )),
              ),
            ),
            TextButton(
              onPressed: () async {
                ///If the widget was not in the widget tree
                ///pass the widget that has to be converted into image.
                await DavinciCapture.offStage(PreviewWidget());
              },
              child: Text('Capture'),
            )
          ],
        ),
      ),
    );
  }
}

/// This widget is not mounted when the App is mounted.
class PreviewWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container();
  }
}
Related