Create Digital Signature Pad in Flutter for iOS & Android
Last updated Jan 30, 2020Hello guys, in this post we are going to learn how to make digital signature in flutter
Flutter provides a CustomPainter widget to create canvas and draw the paths. Wi this widget we can create ESignature pad
Let's start
Create a class CustomePainter which is extends CustomPainter
class CustomePainter extends CustomPainter { @override |
The CustomPainter has two methods paint() which is create the canvas and shouldRepaint() used to handle the repaint status on canvas.
The Canvas class contains methods to draw different types of shapes
canvas.drawLine();
canvas.drawCircle()
canvas.drawArc()
To draw something on the canvas we need to pass Paint object to the canvas
Paint _linePaint = Paint() |
Here we are using drawLines() method to draw signature on the canvas.
To this method we need to pass point for each coordinate of the user touch
How we will get the user touch points?
By using the GestureDetector() widget we are going to collect all user touch points and pass this points to the canvas
GestureDetector( |
Finally add CustomPainter widget to our main widget and run the app
Complete code
main.dart
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'custome_painter.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
State createState() => _MyAppState();
}
class _MyAppState extends State {
static final List colors = [
Colors.black,
Colors.purple,
Colors.green,
];
static final List lineWidths = [3.0, 5.0, 8.0];
// File imageFile;
int selectedLine = 0;
Color selectedColor = colors[0];
List points = [Point(colors[0], lineWidths[0], [])];
int curFrame = 0;
bool isClear = false;
final GlobalKey _repaintKey = new GlobalKey();
double get strokeWidth => lineWidths[selectedLine];
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: SafeArea(
child: Scaffold(
appBar: AppBar(title: Text("Digital Signature"),backgroundColor: Colors.pink,centerTitle: true,),
body: Container(
color: Colors.grey,
padding: EdgeInsets.all(8),
child: Column(
children: [
Expanded(
child: Container(
color: Colors.white,
margin: EdgeInsets.all(8.0),
child: Stack(
alignment: Alignment.center,
children: [
Positioned(
child: _buildCanvas(),
top: 0.0,
bottom: 0.0,
left: 0.0,
right: 0.0,
),
],
),
),
),
_buildBottom(),
],
),
),
),
),
);
}
Widget _buildCanvas() {
return StatefulBuilder(builder: (context, state) {
return CustomPaint(
painter: CustomePainter(
points: points,
strokeColor: selectedColor,
strokeWidth: strokeWidth,
isClear: isClear,
),
child: GestureDetector(
onPanStart: (details) {
// before painting, set color & strokeWidth.
isClear = false;
points[curFrame].color = selectedColor;
points[curFrame].strokeWidth = strokeWidth;
},
onPanUpdate: (details) {
RenderBox referenceBox = context.findRenderObject();
Offset localPosition =
referenceBox.globalToLocal(details.globalPosition);
state(() {
points[curFrame].points.add(localPosition);
});
},
onPanEnd: (details) {
// preparing for next line painting.
points.add(Point(selectedColor, strokeWidth, []));
curFrame++;
},
),
);
});
}
Widget _buildBottom() {
return Container(
color: Colors.pink,
padding: EdgeInsets.only(top: 15.0, bottom: 15.0),
child: StatefulBuilder(builder: (context, state) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
GestureDetector(
child: Icon(
Icons.brightness_1,
size: 10.0,
color: selectedLine == 0
? Colors.white
: Colors.white.withOpacity(0.5),
),
onTap: () {
state(() {
selectedLine = 0;
});
},
),
GestureDetector(
child: Icon(
Icons.brightness_1,
size: 15.0,
color: selectedLine == 1
? Colors.white
: Colors.white.withOpacity(0.5),
),
onTap: () {
state(() {
selectedLine = 1;
});
},
),
GestureDetector(
child: Icon(
Icons.brightness_1,
size: 20.0,
color: selectedLine == 2
? Colors.white
: Colors.white.withOpacity(0.5),
),
onTap: () {
state(() {
selectedLine = 2;
});
},
),
GestureDetector(
child: Container(
color: selectedColor == colors[0]
? Colors.white
: Colors.white.withOpacity(0.2),
child: Icon(
Icons.create,
color: colors[0],
),
),
onTap: () {
state(() {
selectedColor = colors[0];
});
},
),
GestureDetector(
child: Container(
color: selectedColor == colors[1]
? Colors.white
: Colors.white.withOpacity(0.2),
child: Icon(
Icons.create,
color: colors[1],
),
),
onTap: () {
state(() {
selectedColor = colors[1];
});
},
),
GestureDetector(
child: Container(
color: selectedColor == colors[2]
? Colors.white
: Colors.white.withOpacity(0.2),
child: Icon(
Icons.create,
color: colors[2],
),
),
onTap: () {
state(() {
selectedColor = colors[2];
});
},
),
GestureDetector(
child: Text('clear',style: TextStyle(color: Colors.white),),
onTap: () {
setState(() {
reset();
});
},
),
],
);
}),
);
}
void reset() {
isClear = true;
curFrame = 0;
points.clear();
points.add(Point(selectedColor, strokeWidth, []));
}
}
|
CustomePainter file
class Point {
Color color;
List points;
double strokeWidth = 5.0;
Point(this.color, this.strokeWidth, this.points);
}
class CustomePainter extends CustomPainter {
final double strokeWidth;
final Color strokeColor;
Paint _linePaint;
final bool isClear;
final List points;
CustomePainter({
@required this.points,
@required this.strokeColor,
@required this.strokeWidth,
this.isClear = true,
}) {
_linePaint = Paint()
..color = strokeColor
..strokeWidth = strokeWidth
..strokeCap = StrokeCap.round;
}
void paint(Canvas canvas, Size size) {
if (isClear || points == null || points.length == 0) {
return;
}
for (int i = 0; i < points.length; i++) {
_linePaint..color = points[i].color;
_linePaint..strokeWidth = points[i].strokeWidth;
List curPoints = points[i].points;
if (curPoints == null || curPoints.length == 0) {
break;
}
for (int i = 0; i < curPoints.length - 1; i++) {
if (curPoints[i] != null && curPoints[i + 1] != null)
canvas.drawLine(curPoints[i], curPoints[i + 1], _linePaint);
// canvas.drawPoints(PointMode.polygon, curPoints, _linePaint);
}
}
}
bool shouldRepaint(CustomePainter other) => true;
}
|
Article Contributed By :
|
|
|
|
5839 Views |