Create unique designs with Flutter’s Custom Painter

Discover the power of Flutter’s Custom Painter and create stunning designs for your cross-platform apps. Read on to explore the inner workings of the CustomPainter class and show you how to unleash your creativity.

Abhishek Doshi
Somnio Software — Flutter Agency

--

Among its array of distinctive features, Flutter boasts the Custom Painter, an indispensable tool for creating customized designs. With this nifty tool, you can go beyond the ordinary and design unique designs for your cross-platform apps. In this blog post, we’ll take a closer look at the CustomPainter class, its inner workings, and how you can use it to create eye-catching and personalized designs.

What is a Custom Painter?

A Custom Painter is a powerful tool in Flutter that allows developers to create custom graphics and animations easily. It provides a canvas to draw on, and developers can use this canvas to create any design they can imagine. With a Custom Painter, developers can create complex animations, beautiful designs, and custom widgets that are unique to their app.

How does a Custom Painter work?

By leveraging the paint() method, developers have access to a wide range of painting tools and techniques. They can effortlessly employ shapes, gradients, images, and more to bring their artistic vision to life. Whether it’s rendering intricate geometrical patterns, blending vibrant colors, or seamlessly integrating images, the possibilities are virtually limitless.

This flexibility allows developers to tailor the appearance of their widgets to match their specific requirements and design aesthetics. With just a few lines of code, a Custom Painter empowers developers to create visually captivating and personalized user interfaces.

Using a Custom Painter to create custom designs

One of the most remarkable advantages of utilizing a Custom Painter is its incredible versatility:

  • Bring designs to life: From graphs to logos, create captivating visuals with ease.
  • Engage your audience: Craft custom animations like loading spinners and progress bars.
  • Endless possibilities: Leverage the canvas to draw shapes, lines, and gradients.
  • Add depth and richness: Enhance your designs with images and text.
  • Unlock intricate designs: Clip and transform the canvas for visually captivating artwork.

Creating a triangle with the CustomPainter class

To illustrate the concept, let’s delve into a simple example. Although it may seem straightforward, the potential applications of a triangle widget are vast. You could employ it as a pointer, or animate it to construct pyramids, among other creative uses. While this example demonstrates a simple use-case for Custom Painter, it effectively highlights the underlying power and versatility of this remarkable feature.

By leveraging the CustomPainter class, developers gain the ability to create reusable widgets that can be effortlessly integrated into various parts of their applications. Whether it’s for enhancing the user interface, conveying data visually, or adding captivating animations, Custom Painter provides developers with a robust toolset to bring their ideas to life in a visually appealing and engaging manner.

For creating a custom triangle, we need to create a class which extends CustomPainter. Extending a class with CustomPainter, will need 2 override methods to implement; void paint(Canvas canvas, Size size) and bool shouldRepaint(covariant CustomPainter oldDelegate).

The paint method is called to paint the actual object, and the shouldRepaint method sets whether the painter should be repainted when the canvas is rendered again or not.

Let’s see how these 2 methods are defined:

@override void paint(Canvas canvas, Size size) { final paint = Paint() ..color = Colors.blue ..strokeWidth = 3 ..style = PaintingStyle.fill; canvas.drawPath(getTrianglePath(size.width, size.height), paint); }

First, inside the paint method, we need to create a paint brush i.e., we need to create a Paint object. Here, we create the Paint object and initialized it’s color, strokeWidth and style.

Then, using canvas, we call the drawPath method that will draw our triangle using the paint brush that we created. Here, getTrianglePath is a custom method that looks something like the following:

Path getTrianglePath(double x, double y) { return Path() ..moveTo(0, y) ..lineTo(x / 2, 0) ..lineTo(x, y) ..lineTo(0, y); }

It returns the path that needs to be followed by our paint brush to successfully draw a triangle.

Now, our second method, shouldRepaint simply returns a bool. It looks like this:

@override bool shouldRepaint(covariant CustomPainter oldDelegate) => false;

The entire file looks like the following:

import 'package:flutter/material.dart'; class CustomTriangle extends CustomPainter { const CustomTriangle(); @override void paint(Canvas canvas, Size size) { final paint = Paint() ..color = Colors.blue ..strokeWidth = 3 ..style = PaintingStyle.fill; canvas.drawPath(getTrianglePath(size.width, size.height), paint); } Path getTrianglePath(double x, double y) { return Path() ..moveTo(0, y) ..lineTo(x / 2, 0) ..lineTo(x, y) ..lineTo(0, y); } @override bool shouldRepaint(covariant CustomPainter oldDelegate) => false; }

Using the triangle in the UI

Create a Stateless Widget first. In the widget tree, we need to use a widget called CustomPaint that will take a painter property which is of type CustomPainter (here, we can use our CustomTriangle class that we created).

It can look something like this:

CustomPaint( painter: const CustomTriangle(), child: SizedBox( height: MediaQuery.of(context).size.height / 2, width: MediaQuery.of(context).size.height / 2, ), ),

The child widget defines on which child you need to draw this triangle. Hence, we give a SizedBox so that we can manipulate the height and width of the triangle.

Let’s see how it looks!

You can draw any type of shape, uneven drawings, UIs, etc. using a Custom Painter!

Creating an arrow with the CustomPainter class

We will do it with the simplest approach. We already have a triangle created. Now, we will create a line for the arrow. The line can be created as follows:

import 'package:flutter/material.dart'; class CustomLine extends CustomPainter { const CustomLine(); @override void paint(Canvas canvas, Size size) { final paint = Paint() ..color = Colors.blue ..strokeWidth = 10; const p1 = Offset(0, 0); const p2 = Offset(180, 0); canvas.drawLine(p1, p2, paint); } @override bool shouldRepaint(covariant CustomPainter oldDelegate) => false; }

Here, we are creating two offsets. It means the line will be drawn from (0,0) and go to (180,0) angles with the color blue and a stroke width of 10.

Now, we will use a simple row to align the arrow and line together:

import 'dart:math'; import 'package:custom_painter_example/home/widgets/custom_line.dart'; import 'package:custom_painter_example/home/widgets/custom_triangle.dart'; import 'package:flutter/material.dart'; class HomeView extends StatelessWidget { const HomeView({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const CustomPaint( painter: CustomLine(), child: SizedBox( width: 150, ), ), Transform.rotate( angle: pi / 2, child: const CustomPaint( painter: CustomTriangle(), child: SizedBox( height: 50, width: 50, ), ), ), ], ), ), ); } }

Let’s check out how it looks:

Looking good, right? You can create any such shapes using a Custom Painter!

You can check out the entire example on GitHub.

Why use the Custom Painter?

The Custom Painter is useful for building unique UI elements, visualizing data, creating custom animations, optimizing performance, implementing platform-specific customizations, and developing games. Leveraging Flutter’s expertise in cross-platform development, CustomPainter empowers Flutter developers to build highly customized and visually appealing user interfaces with ease.

Originally published at https://somniosoftware.com.

--

--