Drawing in Flutter using CustomPainter

sharan singh
Flutter Community
Published in
4 min readApr 25, 2019

--

Introduction :

In Flutter everything revolves around the term Widget. Flutter gives you the flexibility to write one code, create some beautiful UI widgets and the app is ready for both iOS and Android.So what actually happens is these widgets that you create are drawn on to your mobile screen Or we can call it as drawn on to the Canvas. Using the same concept we can draw on it and use it as a drawing board.

We will be using custom painter for drawing on the canvas, we will have options to change size, opacity and color of the marker.

The code is available at https://github.com/sharansingh00002/draw

You can also checkout my video with extra code :p to take image for image drawn also :

https://www.youtube.com/watch?v=xHWAE8BNJ1E

Now lets have a look at how this is done :)

CODE TIME

So the first information we need to have is the coordinates of the point on the canvas where the user has interacted with, which we can get simply by using Gesture Detector. We will be using onPanUpdate, onPanStart and onPanEnd properties of gesture detector. onPanStart is used when a user just clicks the screen, that way we can draw a single point but if user drags then the continuous points are obtained using the onPanUpdate and OnPanEnd is to notify user has stopped drawing.

We will be storing the points in a list where each element will have the coordinates as well as paint properties associated with that point.

class DrawingPoints {
Paint paint;
Offset points;
DrawingPoints({this.points, this.paint});
}

In gesture Detector onPanUpdate function will look like

onPanUpdate: (details) {
setState(() {
RenderBox renderBox = context.findRenderObject();
points.add(DrawingPoints(
points: renderBox.globalToLocal(details.globalPosition),
paint: Paint()
..strokeCap = strokeCap
..isAntiAlias = true
..color = selectedColor.withOpacity(opacity)
..strokeWidth = strokeWidth));
});
},
onPanStart: (details) {
setState(() {
RenderBox renderBox = context.findRenderObject();
points.add(DrawingPoints(
points: renderBox.globalToLocal(details.globalPosition),
paint: Paint()
..strokeCap = strokeCap
..isAntiAlias = true
..color = selectedColor.withOpacity(opacity)
..strokeWidth = strokeWidth));
});
},
onPanEnd: (details) {
setState(() {
points.add(null);
});
},

So we are using render box to get the rendering object on which we are drawing and for converting global coordinate system points to the local coordinate system for this box. We will be adding null at the end to mark the end of drawing.

Now let’s have a look at our custom CustomPainter class which is responsible for drawing on the screen.

class DrawingPainter extends CustomPainter {
DrawingPainter({this.pointsList});
List<DrawingPoints> pointsList;
List<Offset> offsetPoints = List();
@override
void paint(Canvas canvas, Size size) {
for (int i = 0; i < pointsList.length - 1; i++) {
if (pointsList[i] != null && pointsList[i + 1] != null) {
canvas.drawLine(pointsList[i].points, pointsList[i +1].points ,
pointsList[i].paint);
} else if (pointsList[i] != null && pointsList[i + 1] == null) {
offsetPoints.clear();
offsetPoints.add(pointsList[i].points);
offsetPoints.add(Offset(
pointsList[i].points.dx + 0.1, pointsList[i].points.dy + 0.1));
canvas.drawPoints(PointMode.points, offsetPoints, pointsList[i].paint);
}
}
}
@override
bool shouldRepaint(DrawingPainter oldDelegate) => oldDelegate.pointsList!=pointsList;
}

We are using Canvas.drawLine function to draw the line but if the user has just tapped on the screen we are using Canvas.drawPoint to draw that point.

We are checking for null because we are adding null when the user stops drawing so that if he starts drawing again the last point of last drawing and the start point of new drawing should not connect.

To clear the screen just clear the pointsList.

Customizations :

So we can add many customizations, as of now I have added the option to change strokeWidth, Opacity and color of the brush.

So for strokeWidth and opacity we can simply use a Slider to change the values and as for Color we are giving some predefined most used colors along with an option to use color picker to select a color of their choice.

These changed values are stored in the Paint object which is associated with each drawing Point, so that each point can have its own characterstics.

Slider(
value: (selectedMode == SelectedMode.StrokeWidth)
? strokeWidth
: opacity,
max: (selectedMode == SelectedMode.StrokeWidth)
? 50.0
: 1.0,
min: 0.0,
onChanged: (val) {
setState(() {
if (selectedMode == SelectedMode.StrokeWidth)
strokeWidth = val;
else
opacity = val;
});
}),

For color picker we are using flutter_colorpicker library by fuyumi https://pub.dartlang.org/packages/flutter_colorpicker

Code for this project is available at github repo :

Checkout how to draw in flutter on my youtube channel:

https://www.youtube.com/watch?v=xHWAE8BNJ1E

If you liked this article make sure to 👏 it below, and for those who want to contribute PR’s are always welcome.

--

--