Unleash your inner artist and bring your UI visions to life with Flutter's powerful CustomPaint widget! This versatile tool allows you to create custom graphics that go beyond the limitations of pre-built widgets. Whether you need to draw simple shapes, intricate designs, or anything in between, Flutter CustomPaint provides the canvas and the tools to make it happen.
At the heart of custom graphics in Flutter lies the CustomPaint widget. It acts as a container that allocates a designated area for your artistic endeavors. Here's a breakdown of its key properties:
Now, let's dive deeper into the CustomPainter class, where the real magic happens.
The CustomPainter class serves as the conductor for your artistic symphony. It inherits functionalities from the base class and provides you with a canvas object and the necessary tools to paint upon it. The heart of this class lies within the paint method:
1 2void paint(Canvas canvas, Size size) { 3 // Your drawing logic goes here! 4}
This method takes two arguments:
Now, let's get our hands dirty and explore how to draw some basic shapes!
Here we’ll delve into the world of drawing fundamental shapes using Flutter's CustomPaint widget and the Canvas object. We'll explore lines, rectangles, circles, and ovals, providing code examples to illustrate each concept.
Lines are a great way to begin your journey with CustomPaint. The drawLine method of the Canvas object allows you to draw a line segment between two specified points. Here's a breakdown of the code:
1class LinePainter extends CustomPainter { 2 3 void paint(Canvas canvas, Size size) { 4 final paint = Paint() 5 ..color = Colors.blue // Set the line color 6 ..strokeWidth = 5.0; // Adjust line thickness as needed 7 8 canvas.drawLine(Offset(0.0, 0.0), Offset(size.width, size.height), paint); 9 } 10 11 12 bool shouldRepaint(CustomPainter oldDelegate) => true; 13} 14
Explanation:
Rectangles are another fundamental building block for creating various UI elements. The drawRect method of the Canvas object comes in handy for drawing rectangles. Let's see how it works:
1class RectanglePainter extends CustomPainter { 2 3 void paint(Canvas canvas, Size size) { 4 final paint = Paint() 5 ..color = Colors.red 6 ..style = PaintingStyle.fill; // Fill the rectangle 7 8 final rect = Rect.fromLTWH(100.0, 50.0, 150.0, 200.0); // Define rectangle dimensions 9 canvas.drawRect(rect, paint); 10 } 11 12 13 bool shouldRepaint(CustomPainter oldDelegate) => true; 14} 15
Explanation:
We define a class named RectanglePainter that extends CustomPainter.
Inside the paint method: a. We create a Paint object, this time specifying a fill style to create a solid rectangle (instead of just an outline). b. We create a Rect object using the Rect.fromLTWH constructor. This constructor takes the following arguments: i. Left coordinate of the rectangle (100.0). ii. Top coordinate of the rectangle (50.0). iii. Width of the rectangle (150.0). iv. Height of the rectangle (200.0).
We use the drawRect method. It takes two arguments: a. The Rect object defining the rectangle's position and dimensions. b. The styling information from the Paint object.
Similar to the previous example, shouldRepaint is set to true.
Running this code will display a solid red rectangle on the CustomPaint widget with the specified dimensions and position.
Moving beyond straight lines and sharp corners, circles and ovals add a touch of roundness to your graphics. The Canvas object provides the drawCircle and drawOval methods for this purpose. Here's an example for circles:
1// Class for drawing a circle 2class CirclePainter extends CustomPainter { 3 4 void paint(Canvas canvas, Size size) { 5 final paint = Paint() 6 ..color = Colors.green 7 ..style = PaintingStyle.fill; // Fill the circle 8 9 final center = Offset(size.width / 2, size.height / 2); 10 final radius = size.width / 4; // Adjust radius as needed 11 canvas.drawCircle(center, radius, paint); 12 } 13 14 15 bool shouldRepaint(CustomPainter oldDelegate) => true; 16}
In this class:
Now that you've mastered basic shapes, let's venture into the realm of more intricate designs using Paths. A Path object allows you to define a sequence of connected straight and curved line segments, enabling the creation of virtually any shape imaginable.
Paths offer various methods for constructing your desired shape. Here's a breakdown of some key methods:
moveTo(x, y): This method defines the starting point of your path. Imagine it as placing the tip of your drawing pen on the canvas.
lineTo(x, y): This method draws a straight line segment from the current position of the path (where you left off) to the specified point (x, y).
quadraticBezierTo(x1, y1, x2, y2): This method draws a smooth quadratic Bézier curve. Think of it as bending a flexible hose between two points (x1, y1) and (x2, y2) to create a curve. The curve's shape depends on the placement of these control points.
arcToPoint(x, y, radius, rotation, largeArc, sweep): This method allows you to draw an arc connecting the current position to a specified point (x, y), with options for controlling the arc's size, rotation, and direction. Imagine drawing a curved segment like a slice of pie.
There are many other path methods available for creating different types of curves and shapes, such as cubicTo for cubic Bézier curves and close to connect the end point to the starting point, forming a closed shape.
Let's put theory into practice by creating a custom heart shape using a Path:
1class HeartPainter extends CustomPainter { 2 3 void paint(Canvas canvas, Size size) { 4 final paint = Paint() 5 ..color = Colors.pink 6 ..style = PaintingStyle.fill; 7 8 final path = Path(); 9 path.moveTo(size.width / 2, size.height / 2); // Start at the center 10 11 // Create the heart shape using various path methods 12 path.quadraticBezierTo(size.width * 0.75, size.height * 0.35, size.width / 2, size.height * 0.2); 13 path.arcToPoint(Offset(size.width * 0.25, size.height * 0.35), radius: Radius.circular(20.0), clockwise: false); 14 path.quadraticBezierTo(size.width / 2, size.height * 0.7, size.width * 0.75, size.height * 0.35); 15 path.close(); // Close the path to create a filled shape 16 17 canvas.drawPath(path, paint); 18 } 19 20 21 bool shouldRepaint(CustomPainter oldDelegate) => true; 22} 23
Explanation:
We define a class named HeartPainter that extends CustomPainter.
Inside the paint method: a. We create a Paint object to define the fill color of the heart. b. We create a Path object. c. We use various path methods to define the heart shape: i. moveTo sets the starting point at the center of the canvas. ii. quadraticBezierTo is used twice to create the top curves of the heart. iii. arcToPoint creates the bottom curve of the heart with a specified radius and direction (counter-clockwise in this case).
Another quadraticBezierTo creates the right curve of the heart.
Finally, close connects the end point to the starting point, resulting in a closed shape that can be filled with color.
We use the drawPath method of the canvas to draw the defined path onto the canvas using the styling information from the Paint object.
Running this code will display a beautiful pink heart shape on the CustomPaint widget.
With Paths, the possibilities for creating custom shapes are vast. Experiment with different combinations of these methods and explore other available path methods to bring your unique design ideas to life!
The CustomPaint widget empowers you to create a vast array of custom graphics in Flutter. From basic shapes to intricate designs, the possibilities are limited only by your imagination. This blog post has equipped you with the fundamental knowledge to get started. Remember, practice makes perfect, so experiment, explore different techniques, and don't be afraid to get creative!
Tired of manually designing screens, coding on weekends, and technical debt? Let DhiWise handle it for you!
You can build an e-commerce store, healthcare app, portfolio, blogging website, social media or admin panel right away. Use our library of 40+ pre-built free templates to create your first application using DhiWise.