Flutter Signature Pad Tutorial

Now flutter is very common in the mobile app development world. Every developer or even clients know about it and its power. In a very short time, spam flutter is on every developer’s mind. The result is awesome, developers are making very good plugins to make development easy, fast and up to the mark. Today in this flutter tutorial I am going to share a wonderful flutter example using a simple plugin which can make flutter signature pad in a few minutes with help of a few lines.

The name of the plugin is “signature” , which work pretty decent work. Let’s start learning how to make flutter signature pad to take any one’s signature or autograph depends upon the app you are making.

Adding Dependencies

dependencies:
  signature: ^3.2.0

Installing It

$ flutter pub get

Finally, Import the plugin

import 'package:signature/signature.dart';

If you have already read my previous tutorials and posts, you were aware that I assume you have basic understanding of flutter development, widgets, state or stateless thing. So I no need to explain each and every step.

Output

signature-pad-image-flutter-fumes-2

To make flutter signature pad we need 2 main classes from “signature” plugin.

  1. SignatureController
  2. Signature

First of all need to make set SignatureController

final SignatureController _controller = SignatureController(
    penStrokeWidth: 5,     //you can set pen stroke with by changing this value
    penColor: Colors.black,  // change your pen color
    exportBackgroundColor: Colors.white,  //set the color you want to see in final result
  );

and in our widgets hierarchy we need to user Signature

 Signature(
                controller: _controller,
                height: 500,   // whatever heigt is needed
                backgroundColor: Colors.blueGrey.shade50,     //set background color of your signature widget
  ),

These two tiny blocks of code are enough to make working signature pad. Now let’s get the signature from the program.

 var data = await _controller.toPngBytes();

All done, you can show, save or do whatever you want to do with this returned data. Your flutter signature pad ready to take anyone’s signature.

Here is the complete flutter source code

import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:image_gallery_saver/image_gallery_saver.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:signature/signature.dart';
import 'package:path_provider/path_provider.dart' as path_provider;

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String path = '/storage/emulated/0/flutterfumes';

  final SignatureController _controller = SignatureController(
    penStrokeWidth: 5,
    penColor: Colors.black,
    exportBackgroundColor: Colors.white,
  );

  @override
  void initState() {
    super.initState();
    _controller.addListener(() => print("Value changed"));
  }

  Future<void> writeToFile(ByteData data, String path) {
    final buffer = data.buffer;
    return new File(path).writeAsBytes(
        buffer.asUint8List(data.offsetInBytes, data.lengthInBytes));
  }

  Future<String> _createFile(var data) async {
    Uint8List bytes = data;

    final result = await ImageGallerySaver.saveImage(bytes);
    print(result);

    return result;
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Builder(
        builder: (context) => Scaffold(
          appBar: AppBar(title: Text('Signature Pad Example')),
          body: ListView(
            children: <Widget>[
              Container(
                height: 100,
                child: Center(
                  child: Text('Draw You Signature'),
                ),
              ),
              //SIGNATURE CANVAS
              Signature(
                controller: _controller,
                height: 500,
                backgroundColor: Colors.blueGrey.shade50,
              ),
              //OK AND CLEAR BUTTONS
              Container(
                decoration: const BoxDecoration(color: Colors.black),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  mainAxisSize: MainAxisSize.max,
                  children: <Widget>[
                    //SHOW EXPORTED IMAGE IN NEW ROUTE
                    IconButton(
                        icon: const Icon(Icons.check),
                        color: Colors.blue,
                        onPressed: () async {
                          if (_controller.isNotEmpty) {
                            var data = await _controller.toPngBytes();

                            Navigator.of(context).push(
                              MaterialPageRoute(
                                builder: (BuildContext context) {
                                  return Scaffold(
                                    appBar: AppBar(),
                                    body: Center(
                                        child: Container(
                                            color: Colors.grey[300],
                                            child: Image.memory(data))),
                                  );
                                },
                              ),
                            );
                          }
                        }),
                    //CLEAR CANVAS
                    IconButton(
                      icon: const Icon(Icons.clear),
                      color: Colors.blue,
                      onPressed: () {
                        setState(() => _controller.clear());
                      },
                    ),
                    IconButton(
                      icon: const Icon(Icons.save),
                      color: Colors.blue,
                      onPressed: () async {
                        if (_controller.isNotEmpty) {
                          var data = await _controller.toPngBytes();

                          if (await Permission.storage.request().isGranted) {
                            // Either the permission was already granted before or the user just granted it.

                            await _createFile(data);

                            Fluttertoast.showToast(msg: 'Signature Saved...');
                          }
                        }
                      },
                    ),
                  ],
                ),
              ),
              Container(
                height: 300,
                child: Center(
                  child: Text('Big container to test scrolling issues'),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

I hope it will help you to learn, make and grow. If you have any question or query feel free to ask in comments.

You can also download source code

Previous Post
Next Post

Comments

Mercy

Hello, thank you very much for this Flutter Signature Pad tutorial, it was super helpful.

I have a few parts that got me a little confused though:
1- I see the “writeToFile” method at the top but I do not see it used anywhere else after its declaration.
2- A lot of variables were declared and named “data”, it was hard to tell which is which.
3- In the “createFile” method, how do I set the directory in the Internal Storage I want the image saved to?

Er. Sandeep Singh Sidhu

Hello, I am glad to hear, you found it useful.

Regarding your questions
1. writeToFile method is the answer of your third question, means, you don’t need to use create file in case you want to save file at your preferred location. In write to file you have already file which have signature content, you need to use path_provider or path lib to get the path where you want to save.
2. You don’t need to bother about the data variable used multiple times, because it is local variable, you can give any name, but as your question concerned, data is local variable and have scope inside the method only, so all variable having same name but different methods treated as different variables in memory.
3. I think it is already cleared.

I hope it will help, leave a comment if you need any further help. Subscribe for more simple but useful Articles and tutorials.

Leave a Reply

Your email address will not be published. Required fields are marked *