How to take a screenshot of the current widget - Flutter
Asked Answered
B

4

47

I need to take a screenshot of the current screen or widget and I need to write it into a file.

Banksia answered 30/6, 2018 at 19:37 Comment(0)
B
43

I tried and found the solution,

import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:ui' as ui;
import 'package:flutter/rendering.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  static GlobalKey previewContainer = GlobalKey();
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {

    return RepaintBoundary(
        key: previewContainer,
      child: Scaffold(
      appBar: AppBar(

        title: Text(widget.title),
      ),
      body: Center(
        child: Column(

          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
            ElevatedButton(
                onPressed: takeScreenShot,
              child: const Text('Take a Screenshot'),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    )
    );
  }
  Future<void> takeScreenShot() async{
    final boundary = previewContainer.currentContext!.findRenderObject() as RenderRepaintBoundary;
    final image = await boundary.toImage();
    final directory = (await getApplicationDocumentsDirectory()).path;
    final byteData = await image.toByteData(format: ui.ImageByteFormat.png);
    final pngBytes = byteData?.buffer.asUint8List();
    final imgFile =File('$directory/screenshot.png');
    imgFile.writeAsBytes(pngBytes!);
  }
}

Finally check your application directory You will find screenshot.png !!

And finally got this output

Banksia answered 30/6, 2018 at 20:0 Comment(8)
I am using this code but not take a full-screen screenshotTawnytawnya
@Tawnytawnya me too. I've checked this github.com/flutter/flutter/issues/17687 but the bug still exists.Trituration
image quality is bad. Is there anyway to control the quality of the screenshot?Millais
Increasing the pixel ratio should improve the quality of the output image. ui.Image image = await boundary.toImage(pixelRatio: 2.0);Merbromin
Is their any way to take screenshot in flutter web application by same method or any other method? I try it but didn't work.Palladian
Unhandled Exception: type 'RenderSemanticsAnnotations' is not a subtype of type 'RenderRepaintBoundary'Swigart
how can we create jpg image? png image is transparent and mixed with background. Please share any suggestion.Draughty
This is awesome and better than the screenshot pubdev package - but - you need to put in await or it will only work occasionally :) await imgFile.writeAsBytes(pngBytes.buffer .asUint8List(pngBytes.offsetInBytes, pngBytes.lengthInBytes));Hectogram
S
35

let's say you want to take a screenshot of the FlutterLogo widget . wrap it in a RepaintBoundary with will creates a separate display list for its child . and provide with a key

var scr= new GlobalKey();
RepaintBoundary(
         key: scr,
         child: new FlutterLogo(size: 50.0,))

and then you can get the pngBytes by converting the boundary to an image

takescrshot() async {
  RenderRepaintBoundary boundary = scr.currentContext.findRenderObject();
  var image = await boundary.toImage();
  var byteData = await image.toByteData(format: ImageByteFormat.png);
  var pngBytes = byteData.buffer.asUint8List();
  print(pngBytes);
  }
Sexcentenary answered 30/6, 2018 at 20:1 Comment(4)
I have a question => my widget Listview has more than 10 items, so the screen can't show all items and the capture image is only showing what we have in the screen. Is any method to capture the whole ListView even if the items is not showing on the screen?Phonogram
@Phonogram I don't think it's possible, simply because those items are not even built, so no one knows how they would look like.Galen
@MarcinSzałek , are you absolutely sure about that? It's important enough that I'm posting a question about it: #57584465Nadenenader
how can we create jpg image? png image is transparent and mixed with background. Please share any suggestion.Draughty
P
10

here's the solution for flutter 2.0+ method for screenshot and share it on social media

 import 'package:flutter/rendering.dart';
        import 'package:flutter/services.dart';
        import 'dart:ui' as ui;
        import 'package:path_provider/path_provider.dart';
        import 'package:share/share.dart';
        
        GlobalKey previewContainer = new GlobalKey();
    
     @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            // Here we take the value from the MyHomePage object that was created by
            // the App.build method, and use it to set our appbar title.
            title: Text(widget.title),
          ),
          body: RepaintBoundary(
            key: previewContainer,
            child: Center(
              // Center is a layout widget. It takes a single child and positions it
              // in the middle of the parent.
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text(
                    'Take Screen Shot',
                  ),
                ],
              ),
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: _captureSocialPng,
            tooltip: 'Increment',
            child: Icon(Icons.camera),
          ), // This trailing comma makes auto-formatting nicer for build methods.
        );
      }
    
        
          Future<void> _captureSocialPng() {
            List<String> imagePaths = [];
            final RenderBox box = context.findRenderObject() as RenderBox;
            return new Future.delayed(const Duration(milliseconds: 20), () async {
              RenderRepaintBoundary? boundary = previewContainer.currentContext!
                  .findRenderObject() as RenderRepaintBoundary?;
              ui.Image image = await boundary!.toImage();
              final directory = (await getApplicationDocumentsDirectory()).path;
              ByteData? byteData =
                  await image.toByteData(format: ui.ImageByteFormat.png);
              Uint8List pngBytes = byteData!.buffer.asUint8List();
              File imgFile = new File('$directory/screenshot.png');
              imagePaths.add(imgFile.path);
              imgFile.writeAsBytes(pngBytes).then((value) async {
                await Share.shareFiles(imagePaths,
                    subject: 'Share',
                    text: 'Check this Out!',
                    sharePositionOrigin: box.localToGlobal(Offset.zero) & box.size);
              }).catchError((onError) {
                print(onError);
              });
            });
          }
Paulettepauley answered 11/9, 2021 at 11:41 Comment(3)
I tried this code. It works but produces a low-quality screenshot. It's kindof blurry. Any idea how to make it sharp?Jannjanna
it works also in 2022 thanksCulbreth
Hey! i got an error when we cast as RenderRepaintBoundary?, says that 'type 'RenderFlex' is not a subtype of type 'RenderRepaintBoundary?' in type cast' when creating the boundaryNiggerhead
E
1

Run

flutter screenshot

It will take the screenshot from your connected device and save that to your folder in which you are doing development it will save flutter_01.jpg like that in your folder

Exemplification answered 28/12, 2020 at 19:1 Comment(3)
This takes the screenshot of my entire screen and not the emulator.Momus
This doesn't capture a widget. It only takes a screenshot of the device's screen.Sumatra
It gives me error: Screenshot not supported for Linux.Connors

© 2022 - 2024 — McMap. All rights reserved.