Anaïs
 · Full-Stack Developer

How to integrate Syncfusion's SignaturePad into FlutterFlow

Short Description

In this example you can see how to create the signature and download the image locally.

This custom widget contains a signature pad that allows users to draw a signature. It distinguishes between web and non-web platforms using kIsWeb.

Example

Custom Widget Code:

Dependencies:

  • syncfusion_flutter_signaturepad: ^22.2.8

  • open_file: ^3.3.2

  • universal_html: ^2.2.3

Before using this syncfusion_flutter_signaturepad package, check out its license.

Code:


// Automatic FlutterFlow imports
import '/backend/schema/structs/index.dart';
import '/backend/supabase/supabase.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 '/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 'dart:html';

import 'package:syncfusion_flutter_signaturepad/signaturepad.dart';
import 'dart:ui' as ui;
import 'dart:io' as io;
import 'package:path_provider/path_provider.dart';
import 'package:open_file/open_file.dart';
import 'package:universal_html/html.dart' show AnchorElement;
import 'package:flutter/foundation.dart' show kIsWeb;
import 'dart:convert';
import 'dart:typed_data';
import 'dart:async';

class SignatureWidget extends StatefulWidget {
  const SignatureWidget({
    Key? key,
    this.width,
    this.height,
  }) : super(key: key);

  final double? width;
  final double? height;

  @override
  _SignatureWidgetState createState() => _SignatureWidgetState();
}

class _SignatureWidgetState extends State<SignatureWidget> {
  GlobalKey<SfSignaturePadState> _signaturePadStateKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(children: [
        SfSignaturePad(
            key: _signaturePadStateKey,
            backgroundColor: Colors.grey,
            strokeColor: Colors.white,
            minimumStrokeWidth: 4.0),
        SizedBox(
          height: 15,
        ),
        Row(children: [
          ElevatedButton(
            onPressed: () async {
              _signaturePadStateKey.currentState!.clear();
            },
            child: Text("Clear"),
          ),
          SizedBox(
            width: 30,
          ),
          ElevatedButton(
            onPressed: () async {
              if (kIsWeb) {
                final canvas = CanvasElement(width: 500, height: 500);
                final context = canvas.context2D;

                //Get the signature in the canvas context.
                _signaturePadStateKey.currentState!.renderToContext2D(context);

                //Get the image from the canvas context
                final blob = await canvas.toBlob('image/png', 1.0);

                //Save the image as Uint8List to use it in local device.
                final completer = Completer<Uint8List>();
                final reader = FileReader();
                reader.readAsArrayBuffer(blob);

                reader.onLoad.listen((_) {
                  final Uint8List imageData =
                      Uint8List.fromList(reader.result as List<int>);
                  completer.complete(imageData);
                });

                Uint8List imageData = await completer.future;
                // Now you can use the Uint8List as needed.

                // Create a blob from the Uint8List.
                final blobImage = Blob([imageData]);

                // Create an anchor element with a download link.
                final anchor =
                    AnchorElement(href: Url.createObjectUrlFromBlob(blobImage))
                      ..setAttribute("download", "signature.png")
                      ..text = "Download Image";

                // Append the anchor element to the document body and click it.
                document.body!.append(anchor);
                anchor.click();

                // Remove the anchor element from the document.
                anchor.remove();
              } else {
                ui.Image image = await _signaturePadStateKey.currentState!
                    .toImage(pixelRatio: 2.0);
                final byteData =
                    await image.toByteData(format: ui.ImageByteFormat.png);
                final Uint8List imageBytes = byteData!.buffer.asUint8List(
                    byteData.offsetInBytes, byteData.lengthInBytes);

                final String path =
                    (await getApplicationSupportDirectory()).path;
                final String fileName = io.Platform.isWindows
                    ? "$path\\signature.png"
                    : "$path/signature.png";
                final io.File file = io.File(fileName);
                await file.writeAsBytes(imageBytes, flush: true);
                OpenFile.open(fileName);
              }
            },
            child: Text("Save As Image"),
          ),
        ])
      ]),
      height: 300,
      width: 300,
    );
  }
}

Some notes about the code

Inside the "Save As Image" button's onPressed function:

If the platform is web (kIsWeb is true), the signature from the SfSignaturePad is rendered onto a canvas, then converted to a Blob (binary large object) and finally to a downloadable image.

If it's not a web platform, the signature is converted to an image, saved as a PNG file, and then opened using the OpenFile package.

Additional resources

8
2 replies