The art of sharing screens: Take a ScreenShot and Share it.

Abdullah Ahmed Soomro
Blocship
Published in
5 min readJul 29, 2023

Hello Guys!
Hope you are all well, In this, we will learn how to take a screenshot without using the screenshot package and share it with others in Flutter. We’ll go step by step for better understanding.

The flow of this tutorial will be:

  • Capture a visible widget.
  • Saving a screenshot into your phone and Sharing them.
  • Share a screenshot without Saving them into your phone.

Packages that we are using in this tutorial:

  • share_plus: (Latest version)

Capture a visible widget and an invisible widget:

First of all, add the share_plus dependency in pubspec.yaml file of your project, under the dependencies, as shown below:

then run this command into your project terminal:

flutter pub add get

Now you have to set minSdkVersion at least 19 because share_plus requires a higher Android SDK version.

file directory: [your_project]\android\app\build.gradle:

Here are the imports that we gonna use!

// For handling byte data and typed arrays (e.g., Uint8List)
import 'dart:typed_data';

// For low-level graphics operations, capturing widgets as images, etc.
import 'dart:ui' as ui;

// Flutter's Material Design framework for building UIs
import 'package:flutter/material.dart';

// For rendering widgets and capturing widget subtrees
import 'package:flutter/rendering.dart';

// For sharing content with other apps on the device
import 'package:share_plus/share_plus.dart';

Now, move on to your widget, where you want to take a screenshot. Inside that widget class make a Global key.

/// Global Key for taking screenShot
final GlobalKey globalKey = GlobalKey();

Wrap your widget with RepaintBoundary(), whom you want to take screenshot and assign the global key to its key property:

RepaintBoundary(
key: globalKey,
child: Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text('Screenshot Page'),
),
body: Center(
child: ElevatedButton(
onPressed: (){},
child: const Text('Take Screenshot'),
),
),
),
);

Now, we need a function that takes a screenshot and shares it:

  Future<void> _captureScreenShot() async {
RenderRepaintBoundary boundary =
globalKey.currentContext!.findRenderObject() as RenderRepaintBoundary;
ui.Image image = await boundary.toImage(pixelRatio: 2);
ByteData byteData =
await image.toByteData(format: ui.ImageByteFormat.png) as ByteData;
Uint8List pngBytes = byteData.buffer.asUint8List();
await Share.shareXFiles([XFile.fromData(pngBytes, mimeType: 'image/png')]);
}

Let’s break down the _captureScreenshot function step by step:

Step# 01:

RenderRepaintBoundary boundary = globalKey.currentContext!.findRenderObject() as RenderRepaintBoundary;
  • Here, we create a variable named boundary of type RenderRepaintBoundary. This class allows us to capture a widget subtree and convert it into an image.
  • globalKey.currentContext returns the BuildContext associated with the globalKey.
  • findRenderObject() is called on the currentContext, which returns the render object associated with that BuildContext.
  • We use a typecast as RenderRepaintBoundary to explicitly convert the rendered object to RenderRepaintBoundary, as we know that the widget associated with globalKey is a RepaintBoundary.

Step# 02:

ui.Image image = await boundary.toImage(pixelRatio: 2);
  • Here, we use the boundary object we obtained in the previous step to convert the widget subtree into an ui.Image object.
  • And ui refers to the dart:ui that we import above.
  • toImage() is a method of RenderRepaintBoundary class that takes an optional parameter pixelRatio. The pixelRatio specifies the scale of the image, which can be used to create higher-resolution screenshots.
  • In this example, we set pixelRatio to 2, which means the screenshot will have twice the resolution compared to the screen's native resolution.

Step# 03:

ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png) as ByteData;
  • We utilise the toByteData() method to change the ui.Image object into a ByteData object after acquiring it.
  • The format argument, which is optional, is sent to the toByteData() function and determines the picture format to use. To obtain the screenshot in PNG format in this instance, we utilise ui.ImageByteFormat.png.
  • The data is subsequently saved in the byteData variable when toByteData() returns its outcome. To clearly state the data type, we typecast as ByteData.

Step# 04:

Uint8List pngBytes = byteData.buffer.asUint8List();
  • After obtaining the ByteData object, we access the underlying data buffer, which houses the picture bytes, using the buffer property.
  • The data buffer is then transformed into an Uint8List, which depicts the screenshot as a collection of bytes, using the asUint8List() function.

Step# 05:

await Share.shareXFiles([XFile.fromData(pngBytes, mimeType: 'image/png')]);
  • The screenshot is then shared as a file using the Share plugin.
  • The share_plus package has a function called Share.shareXFiles() that accepts a list of XFile objects as an input. A shareable file is represented by an XFile.
  • The Uint8List (pngBytes) holding the image data is passed to XFile.fromData() when creating an XFile, and the mimeType is set to ‘image/png’ to denote that the file is in PNG format.
  • The await keyword is used to delay doing any more (if necessary) actions until the sharing procedure has finished.

That’s it! With the help of the share_plus package, this function shares a screenshot it has taken of the widget subtree connected to the globalKey.

That’s it! With the help of the share_plus package, this function shares a screenshot it has taken of the widget subtree connected to the globalKey.

Conclusion:

In this article, we looked at the technique for sharing screens in a Flutter application by taking a screenshot and doing so. Using the RepaintBoundary widget and the dart:ui library, we discovered how to snap a screenshot of a widget that is now displayed. The widget subtree had to be transformed into an ui.Image, then into ByteData, and then into an Uint8List that represented the image bytes. We quickly shared the screenshot with other applications on the smartphone with the aid of the share_plus package.

Having a grasp of these ideas, you are now able to include screen sharing features in your Flutter apps, facilitating smooth content sharing and user interaction.
Consider purchasing me a coffee if you found this lesson useful and want to support the production of further material. Your support will encourage me to continue producing useful and educational lessons for the community.

I appreciate you joining me on this adventure, and I wish you much success as you discover and develop fantastic Flutter apps! Happy programming!

--

--