Custom Paint in Flutter

Ankit Gupta
4 min readSep 5, 2020


So once again we are back in our class and today we are going to have some fun with Custom Paints in Flutter, So let's grab our paintbrush and enter our class.

So let's look at what we are building today

Yes, a Smiley with some animation.

and our code looks like

Before we start we need to look for something important the coordinate axis in Flutter.

Flutter axis

The left topmost corner of our device is the (0,0) origin and the x-axis corresponds to the width of the device screen and the y-axis is the height of the device screen.

The second thing is to get Offset( x, y ) we are going to use this in our entire custom paint, offset is just a point on the screen with corresponding x and y values like any other coordinate (x,y) in our graph paper.

We are going to deal with only custom paint for animation we can refer to our previous article.

So in our parent's build method, we are providing a Container with a height and width of 300 this is important because the painter working on the canvas will use his parent's constraints to get the height and width to set up the canvas to draw on.

We have implemented the animation using Animated Builder and have assigned the child a CustomPaint which takes a painter which we are going to create now.

class Smiley extends CustomPainter {@override  void paint(Canvas canvas, Size size) {}@override  bool shouldRepaint(CustomPainter oldDelegate) { 
return true;

For our custom animation, we create a class smiley that extends CustomPainter now this class should override two important methods Paint and ShouldRepaint.

Paint is the method where the actual magic of painting a canvas happens the size of the canvas depends on the size of its parent widget which in this case is a container with a height and width of 300.

ShouldRepaint is an optimization that decides the rebuilding of painting the canvas we simply return here true.

As a general rule before hitting the canvas, we need to choose our paintbrush. And now for choosing our paintbrush we are going to use a class called Paint.

Paint _paintCircle;  // for yellow circle
Paint _paintDetails; // for details of eyes and nose
Paint _smilePaint; // for smile
Smiley() {

// face paint
_paintCircle = Paint()
..color = Colors.yellow = PaintingStyle.fill;

// eyes and nose
_paintDetails = Paint()
..color = Colors.redAccent[700] = PaintingStyle.fill
..strokeCap = StrokeCap.round
..strokeWidth = 10;
// smile
_smilePaint = Paint()
..color = Colors.redAccent[700] = PaintingStyle.stroke
..strokeWidth = 16
..strokeCap = StrokeCap.round;

here we are creating 3 paintbrushes as in the description for face for eyes and nose and a smile. We need to initialize how our paintbrush should be and their properties in the constructor.

Once we select our brushes now we are ready to paint on the canvas first let's paint the face.

//     drawing face background  
Offset(size.width / 2, size.height / 2), size.width / 2, _paintCircle

the first argument is offset which defines the center of the circle, we calculate it to be at the center of the container, the second argument is the radius of the circle and the third argument is the brush itself. This is enough to just paint the circle.

//     drawing eyes  

Offset(size.width * 0.3, size.height * 0.3), 16, _paintDetails);
canvas.drawCircle(Offset(size.width - size.width * 0.3, size.height *0.3), 16, _paintDetails);

the same process we repeat for drawing both eyes, we just replaced some offset and paintbrush.

double x = size.width / 2; 
double y = size.height / 2;
// drawing nose final Path _path = Path();
_path.moveTo(x - 10, y);
_path.lineTo(y, y - 20);
_path.lineTo(x + 10, y);
canvas.drawPath(_path, _paintDetails);

Here for the nose, we need to make a triangle for which we declare and initialize a Path object it is the job of this path to trace the point we declared in its attributes.

path.moveTo() this just moves the point of our paintbrush as we pull our hand from the canvas and start painting on another area of the canvas this does not paint but just shifts our brush.

path.lineTo() and path.close() the path enclosed between this gets painted.

now canvas.drawPath is the Function that executes our painting of the nose.

final smile = Path();   
smile.moveTo(size.width * 0.7, size.height * 0.7); smile.arcToPoint(Offset(size.width * 0.3, size.height * 0.7), radius: Radius.circular(70));
canvas.drawPath(smile, _smilePaint);

At last, we need to draw the smile the only different thing here is arcToPoint() which takes the final offset till where we have to draw our arc, along with the radius which specifies the curve of our arc.

With this, we pass our path (smile) and a paintbrush to canvas.drawPath to complete our smile.

So in the end keep Smiling and keep coding.