Drawing Custom Shapes and Lines Using Canvas and Path in Flutter
In order to draw custom shapes and lines in Flutter, there are basically four things involved:
- CustomPaint (It’s the exhibitor who gives you a paper to draw on, and then exhibits what you have drawn) 🖼️
- CustomPainter (It’s you! The painter!) 👨🎨
- Paint (It’s your brush) 🎨🖌️
- Canvas (It’s your paper) ⬜
Yes, it’s that simple!
So let’s get started by creating our main file:
The drawing will happen in the
As usual, our page starts with
Scaffold which has an
appBar and a
body which is set to an instance of
The canvas is created and provided to you by the
CustomPaint widget which has three important properties:
painter: This is an instance of the
CustomPainterclass which draws the first layer of your painting on the canvas.
child: You can set this to any widget you want. After the painter is done with painting, the child widget is shown on top of the painting.
foregroundPaint: Finally, this paint is drawn on top of the two previous layers.
As I said, the
CustomPaint object creates the
canvas and gives it to the
foregroundPaint objects so that they can draw on it.
The Size of the Canvas
But what will be the size of the canvas? The same size as the whole of the screen? Half of the screen? or what?
CustomPaint object creates a canvas the same size as the size of the
child parameter. If the
child parameter is not provided (yes, that’s optional), the canvas size is determined by the
size parameter that you can provide to
CustomPaint object when instantiating it.
In our example, the
child is a Center widget which is as big as the screen. Therefore, our
canvas will be as big as the whole screen too!
If you are wondering why the Center widget is as big as the whole screen, you can read this article I recently wrote about the Center widget: Understanding Center Widget in Flutter
The upper left corner of the canvas is called origin. It’s the point with
(0, 0) coordinates. The coordinates of the lower right corner of the canvas are
painter parameter is of type
This simply means that your painter class (that we are going to create) must extend the
You would usually name your CustomPainter class according to what it’s going to paint. If it’s going to paint a sky, name it SkyPainter. If it’s going to draw a face, name it FacePainter. If you are going to draw a gun 🔫 make sure you read this first:
If a person has to engage in gun drawing, one had better be sure that they do so in the right situation. There are circumstances in which it isn’t legal to draw a firearm. Continue reading at: http://gunbelts.com/blog/when-is-drawing-your-gun-legal/
Since I mainly intend to draw a dashed curved line on the canvas, I’d like to name my painter “CurvePainter”:
As you see, my painter has extended the
CustomPainter class has two important functions to override:
paint: The actual painting happens here. Did you notice the two parameters provided to this function? In this function, you have access to the
canvasobject which is indeed your paper, and also the size of the canvas on which you are going to draw.
shouldRepaint: In this function, you should either return
false. If your painting depends on a variable and that variable changes, you return true here, so that Flutter knows that it has to call the paint method to repaint your painting. Otherwise, return false here to indicate you don’t need a redraw.
Drawing Lines and Shapes
Now everything is ready for you to start drawing. The
canvas is ready and we know its
canvas object provided to you has several helper functions that will help you draw something, to name a few:
drawLine(Offset p1, Offset p2, Paint paint)
Draws a line from point 1 to point 2, with the given paint.
drawCircle(Offset c, double radius, Paint paint)
Draws a circle centered at the point given that has the
radius given by the second argument, with the
paint given in the third argument.
drawPath(Path path, Paint paint)
Draws the given
path with the given
moveTo(double x, double y)
Before you start drawing, your pen is by default on the origin point i.e. the top-left corner of the canvas. You can move your pen though, before starting to draw, with this function.
In all the shapes you draw, whether they are filled or stroked (or both) is controlled by
Ok, let’s draw something real. I will draw a line, a circle and a path for you, and leave you with exploring the rest of the functions!
In the above example, I have first created the paint (which is like my pen) and have set the color and width of my pen. Then I have used the
drawLine method to draw a line from the middle of the left edge to the middle of the right edge of the canvas:
👉 Note how the “Blade Runner” text widget (which is the
child parameter of
CustomPaint) has been drawn after the
painter is done. If you had provided a third
foregroundPaint parameter, it would be drawn on top of the child widget.
Now let’s draw a blue circle, at the center of the canvas:
As you can see, I used the same paint, but first changed its color to blue, and also set its style to
stroke (rather than
fill), so that the circle does not get filled. I’ve specified the center point of the canvas by
Offset(size.width/2, size.height/2) and decided the
radius of the circle to be proportional to the canvas width:
Tip: I could simply set the radius to some number like 10 or whatever, but since the screen could be of any size, it’s better to size our objects according to the size of our canvas.
Drawing a Path
Now let’s draw a check mark ✔️ using the path object, below the circle.
For this to happen, I have first moved my pen to a coordinate below the circle (using
moveTo), and then added two lines to the path (using
lineTo). You just need to imagine the appropriate X and Y coordinates, or to be more accurate, grab a piece of paper and calculate them patiently. The result of the code above is:
It’s possible to close the path by calling
Do you want this closed path to be filled with color? No problem! Just change the style of your pen to
The result is:
The source code of this article is available on GitHub.
In the next article, I will show you “how to draw a dashed curved line.
Until then, stay tuned and thanks for reading!