Ya'll know Chris Coffee's article(https://community.flutterflow.io/community-tutorials/post/flutter-flow-how-to-screenshot-any-widget-dbWT5hlhBUbQbnh) on how to screenshot a widget. I recently used his code and modified a little bit and added a share action on top of it. Thought I'd share it here. I made a short video: https://youtu.be/PWfZMJEezWA. Here is the code for the custom widget and action.
// Automatic FlutterFlow imports
import '/backend/backend.dart';
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/custom_code/actions/index.dart'; // Imports other custom actions
import '/flutter_flow/custom_functions.dart'; // Imports custom functions
import 'package:flutter/material.dart';
// Begin custom action code
// DO NOT REMOVE OR MODIFY THE CODE ABOVE!
import 'dart:typed_data';
import 'package:share_plus/share_plus.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';
Future<void> shareScreenshot(FFUploadedFile imageBytes) async {
try {
if (imageBytes.bytes == null) {
print('Error: imageBytes is null');
return;
}
final Uint8List bytes = imageBytes.bytes!; // Ensure non-null
// Save the file locally before sharing
final tempDir = await getTemporaryDirectory();
final filePath = '${tempDir.path}/${imageBytes.name ?? "screenshot.png"}';
final file = File(filePath);
await file.writeAsBytes(bytes);
// Share the image
await Share.shareXFiles([XFile(filePath)], text: "Check out this quote!");
} catch (e) {
print('Error sharing screenshot: $e');
}
}
// Set your action name, define your arguments and return parameter,
// and then add the boilerplate code using the green button on the right!
// Automatic FlutterFlow imports
import '/backend/backend.dart';
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/custom_code/widgets/index.dart'; // Imports other custom widgets
import '/custom_code/actions/index.dart'; // Imports custom actions
import '/flutter_flow/custom_functions.dart'; // Imports custom functions
import 'package:flutter/material.dart';
// Begin custom widget code
// DO NOT REMOVE OR MODIFY THE CODE ABOVE!
import 'index.dart'; // Imports other custom widgets
/* Add these to pubspec.yaml:
screenshot: ^2.1.0
*/
import 'package:screenshot/screenshot.dart';
class WidgetScreenshot extends StatefulWidget {
const WidgetScreenshot({
Key? key,
this.width,
this.height,
required this.screenshotChild,
this.onScreenshotCaptured,
}) : super(key: key);
final double? width;
final double? height;
final Widget Function()? screenshotChild;
final Future Function(FFUploadedFile screenshot)? onScreenshotCaptured;
@override
_WidgetScreenshotState createState() => _WidgetScreenshotState();
}
class _WidgetScreenshotState extends State<WidgetScreenshot> {
final screenshotController = ScreenshotController();
Future captureScreenshot() async {
try {
final Uint8List? capturedImage = await screenshotController.capture();
if (capturedImage != null && widget.onScreenshotCaptured != null) {
final timestamp = DateTime.now().millisecondsSinceEpoch;
final screenshotFile = FFUploadedFile(
name: 'screenshot_$timestamp.png',
bytes: capturedImage,
);
await widget.onScreenshotCaptured!(screenshotFile);
}
} catch (e) {
print('Error capturing screenshot: $e');
}
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
// Screenshot Container
Container(
width: widget.width,
height: widget.height,
child: Screenshot(
controller: screenshotController,
child: widget.screenshotChild?.call() ?? Container(),
),
),
// Share Button Positioned Inside an Align + Row
Align(
alignment: AlignmentDirectional(0, 1), // Bottom of the container
child: Container(
width: double.infinity,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(1, -1), // Top-right placement
child: Padding(
padding:
EdgeInsets.only(top: 192), // Moves the button down by 192px
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
decoration: BoxDecoration(
color: FlutterFlowTheme.of(context)
.secondaryBackground, // Background color
borderRadius:
BorderRadius.circular(8), // Rounded corners
),
child: IconButton(
icon: Icon(
Icons.near_me_rounded, // Replacing FaIcon correctly
color: FlutterFlowTheme.of(context)
.primaryText, // Icon color
size: 18, // Ensure the same size as FaIcon
),
onPressed: captureScreenshot, // Captures the screenshot
iconSize: 24, // Ensures proper tap area
),
),
],
),
),
),
),
)
],
);
}
}
// Set your widget name, define your parameter, and then add the
// boilerplate code using the green button on the right!