Building a Drawing App in Flutter
Learn how to create a drawing app in Flutter and explore Flutter’s capability to render and control a custom UI with the help of CustomPaint widgets. By Samarth Agarwal.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Building a Drawing App in Flutter
35 mins
- Getting Started
- Introducing Flutter Canvas and CustomPaint
- Using the CustomPaint Widget
- Understanding Canvas Basics
- Drawing Paths
- Changing the Stroke, Color and Width
- Diving Into Code
- Using GestureDetector
- Drawing a Single Path
- Drawing Multiple Paths
- Adding Stroke Color and Width
- Changing Stroke Color
- Changing Stroke Width
- Optimizing Your App
- Drawing Multiple Lines
- Using StreamBuilders and Two CustomPaint widgets
- Saving the Drawing
- Creating New and Save Buttons
- Using the Plugin
- Where to Go From Here
Drawing the UI is one of the core features of every visual app framework. In this tutorial, you’ll build a drawing app in Flutter to explore Flutter’s capability to render and control a custom user interface. You’ll learn to control every pixel on the screen with the help of CustomPaint widgets.
Here’s a preview of the app you’ll build:
To build this drawing app, you’ll harness the rendering powers and the pixel-level control that Flutter offers. It allows you to control each pixel on the screen — you can render anything you want, any where you want.
While building this app, you’ll learn about:
- Using the
CustomPaint
widget to draw UI pixel-by-pixel - The drawing basics and using a
Canvas
- Detecting user input using
GestureDetector
and drawing a path - Drawing multiple paths on the screen
- Changing painter colors and stroke widths
- Clearing and saving your drawings
Getting Started
Download the starter project by clicking the Download Materials button at the top or bottom of the tutorial.
Unzip the downloaded file and open it with Android Studio 4.1 or later. You can use Visual Studio Code instead, but if you do, you’ll need to tweak some instructions to follow along.
Click Open an existing Android Studio project and choose the starter folder from your unzipped download.
Run the flutter create . command in the starter folder to generate the android and ios folders. Next, download your dependencies by double-clicking pubspec.yaml on the left panel, then clicking pub get at the top of your screen. To avoid problems, delete the test folder, which Flutter generated when you executed the flutter create . command.
Finally, build and run to see this:
Here are a few files you’ll see in the starter project’s lib folder.
-
main.dart: This is the main file that acts as the entry point for the app. It contains a
MyApp
that containsMaterialApp
. This widget usesDrawingPage
as the child. -
drawing_page.dart: This file contains most of the code. It renders the widgets that you saw in the app preview. The drawing area, the save and clear buttons, the color toolbar and the stroke toolbar are all rendered inside
DrawingPage
. -
drawn_line.dart: This file is a simple model class
DrawnLine
for a typical path drawn on the screen. Each path that is drawn contains aList
of points on the screen (List<Offset>
), a color (Color
) and a stroke width (double
). You’ll use this class when drawing paths. “Path” might be a more relevent name for this class, but since it’s already a Flutter class, you use the nameDrawnLine
. Feel free to rename it, but be sure to change the rest of the code accordingly. -
sketcher.dart:
Sketcher
is a class that extendsCustomPainter
and is used in combination with theCustomPaint
to draw on the screen. This class contains the logic to drawDrawnLine
s on the screen. -
main_learning.dart: You’ll use this file to show the basics of drawing simple shapes on the
Canvas
.
Here’s what your app’s user interface (UI) will look like:
- Drawing Space: This is the light yellow space where the user will draw with their finger.
- Color Toolbar: This allows the user to change the currently selected color to one of seven colors.
- New/Clear Button: This button allows the user to clear the canvas and start afresh.
- Save Button: This lets the user save whatever is currently drawn on the screen as an image on the device. The saved image appears in the phone’s Gallery (on Android) and Photos (on iOS).
- Stroke Toolbar: This contains buttons that allow the user to change the current stroke width to a specific size. There are three stroke sizes — small, medium and large.
ColorToolbar
, it also contains the New/Clear buttons.
Introducing Flutter Canvas and CustomPaint
Flutter’s Canvas
is an interface for recording graphical operations. It can be used to draw shapes, images, texts and nearly everything else on the screen with pixel precision. To create and access the Canvas
, you’ll use a widget called CustomPaint
. You’ll also use a painter
parameter that contains all the painting logic and extends CustomPainter
.
Using the CustomPaint Widget
Here’s a code snippet that includes a Container
and has a CustomPaint
as its child:
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
color: Colors.yellow[100],
child: CustomPaint(
painter: MyCustomPainter(),
),
);
}
}
In the code snippet above, you create a widget called MyWidget
that renders a Container
. The Container
contains a CustomPaint
as its child. Have a quick look at the most simple implementation of MyCustomPainter
:
// 1
class MyCustomPainter extends CustomPainter {
// 2
@override
void paint(Canvas canvas, Size size) {
}
// 4
@override
bool shouldRepaint(MyCustomPainter delegate) {
return true;
}
}
Here’s what’s going on in the code snippet above:
- You create the
MyCustomPainter
, which extendsCustomPainter
. Once you create the class with this signature, your IDE will detect errors and suggest you implement the two missing methods –paint()
andshouldRepaint()
. -
paint()
contains all the drawing and painting logic. It receives two arguments:Canvas
andSize
. You’ll use both of these while writing the drawing code. All the drawing code goes within the body of this method, where you’ll gain access to various methods likedrawLine()
,drawArc()
,drawPath()
,drawPoints()
,drawRect()
and many more. To find all available methods, see the official Flutter documentation. TheSize
parameter allows you to draw considering the size of the canvas. -
shouldRepaint()
is an optimization method that’s called whenever you create a newCustomPaint
. If the new instance represents different information than the old one, the method returns true. Otherwise, it returns false.
The Sketcher
(in sketcher.dart) available in the starter project is a similar class that extends CustomPainter
.