Introduction

The design might not be what every developer likes to focus on when creating their app, but surprisingly you can easily make your design stand out with just a simple widget called CustomPaint.

If you would rather prefer watching a video for the content you can always check out the tutorial on YouTube:

Initial Setup

Let’s go ahead and create a simple project which will just be the autogenerated counter project for now and set the theme to dark so we don’t have to care about the text color.

return MaterialApp(

debugShowCheckedModeBanner: false, // Hide the debug banner

title: 'Flutter Demo',

theme: ThemeData(

brightness: Brightness.dark, // Dark theme

primarySwatch: Colors.blue,

),

home: MyHomePage(

title: 'Flutter Demo Home Page'),

);

}

Now we can begin setting up our CustomPaint and let’s do that by wrapping our whole body of MyHomePage . The reason we do that is because all the children in the body will be rendered on top of the CustomPaint .

return Scaffold(

body: CustomPaint(

painter: , // We are going to use a CustomPainter widget here

child: Center(

child: Column(

mainAxisAlignment: MainAxisAlignment.center,

children: <Widget>[

Text(

'You have pushed the button this many times:',

),

Text(

'$_counter',

style: Theme.of(context).textTheme.display1,

),

],

),

),

),

);

Our own CustomPainter

1. Setting up a CustomPainter

So let’s now go ahead and create our CustomPainter and in this class, which extends CustomPainter, we can easily set up how our painter is going to paint. Let’s start by setting up our BluePainter class.

class BluePainter extends CustomPainter {

@override

void paint(Canvas canvas, Size size) {

final height = size.height;

final width = size.width;

Paint paint = Paint();

} @override

bool shouldRepaint(CustomPainter oldDelegate) {

return oldDelegate != this;

}

}

We can see that we have two methods that needs to be implemented as we extend the CustomPainter and that is the paint method and the shouldRepaint method. We simply set the ShouldRepaint to return the old paint if it hasn’t changed.

For the paint method I have gone ahead and created two final variables and this is just to remove the boilerplate code of having to write size. each time we want the height or width value. For the Paint variable, that is just a description of what style we want to paint in, I will go over that later in the article.

2. Drawing a blue rectangle

So the first part of our paint is to simply have the whole background a darker tint of blue so we can later paint an oval shape on top of that with a lighter shade of blue.

Path mainBackground = Path();

mainBackground.addRect(Rect.fromLTRB(0, 0, width, height));

paint.color = Colors.blue.shade700;

canvas.drawPath(mainBackground, paint);

We start by creating a Path and to not go too deep on this one you can think of it as a flat plain. First we create the Path which we just call the mainBackground as this will have a darker shade of blue. Then we start by making it a simple rectangle so we can cover the whole screen with it and then draw it on the canvas. Don’t forget to add BluePainter to the CustomPaint widget like so: painter: BluePainter(), now we should have a page that is completely blue with our counter on top of it.

Now that it is working we can make the more complicated oval on top of this blue background and just to clear some things up before we start is that when creating a Path we always start at the coordinates of x = 0 and y = 0 which will translate to top left of the app. Now when we have that out of the way we can start!

3. Designing the oval

We first define our Path variable and start the painting at 20% of the height.

Path ovalPath = Path(); // Start paint from 20% height to the left

ovalPath.moveTo(0, height * 0.2);

We then define our first curve and to do this we have quadtraticBezierTo method which takes control point from the x1 and y2 and then the position it should paint to which is the x2 and y2. The control point is where we are going to curve the line to and we paint it to have the height as we want the curve to be more rounded.

// paint a curve from current position to middle of the screen

ovalPath.quadraticBezierTo(

width * 0.45, height * 0.25, width * 0.51, height * 0.5);

Now we finish of the curve and paint the remaining line to the bottom left of the app. So in essence we have two curves where x2 and y2 are the position it is going to draw to while x1 and y1 are the direction the line is curving too. Remember to play around with the numbers for the control point so you get something that you want!

// Paint a curve from current position to bottom left of screen at // width * 0.1 ovalPath.quadraticBezierTo(

width * 0.58, height * 0.8, width * 0.1, height); // draw remaining line to bottom left side

ovalPath.lineTo(0, height);

We then simple close the path to make it go back to where the path originated from which was 0, height * 0.2, or to make it more clear, the left side at 20% height. We simple apply the new shade of blue and paint it to the canvas .

// Close line to reset it back

ovalPath.close();

paint.color = Colors.blue.shade600;

canvas.drawPath(ovalPath, paint);

Results

Code below

Conclusion

CustomPaint is a great way to spice up a very simple design and this is just scratching the surface. You can find me in a lot of places so don’t be afraid to drop by!