ITKarma picture

Flutter offers various widgets for working with a specific set of shapes, for example, ClipRect , ClipRRect , ClipOval . But there is also ClipPath , with which we can create any types of shapes.

In this article, we will focus on what you can do using ClipPath and CustomClipper . Let's go!

Content :


Thanks to ClipPath we can create very complex and unusual shapes. The clipper property of ClipPath

will help us with this.
@override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey, body: Center( child: ClipPath( clipper: MyCustomClipper(),//<-- child: Container( width: 200, height: 200, color:, ), ), ), ); } 

The value for clipper must be an instance of a class that CDMY0CDMY inherits and overrides two methods.

class MyCustomClipper extends CustomClipper<Path> { @override Path getClip(Size size) { Path path=Path(); return path; } @override bool shouldReclip(CustomClipper<Path> oldClipper) => false } 

The getClip method is called every time when you want to update our described figure. As a parameter, the method receives CDMY1CDMY, which contains the values ​​of height and width of the widget transferred to CDMY2CDMY by CDMY3CDMY.

shouldReclip is called when CDMY4CDMY passed a new instance of the class. If the new instance is different from the old, then the method should return CDMY5CDMY, otherwise CDMY6CDMY.

We need to describe the figure inside CDMY7CDMY. It's not very difficult, but first you need to deal with the basics of graphics.

ITKarma picture

As shown in the above figure, each point on the graph is described through a coordinate (CDMY8CDMY, CDMY9CDMY). CDMY10CDMY is the horizontal axis, and CDMY11CDMY is the vertical axis. The construction of the figure begins with the upper left corner, whose coordinate (CDMY12CDMY, CDMY13CDMY).

Let's look at the available methods for building shapes. Using these methods, you can create your own shapes.


This method is used to build a segment from the current point to the specified one.

ITKarma picture

As shown in Figure (a) above, the default path starts at point CDMY14CDMY. Now add a new segment to CDMY15CDMY, and then CDMY16CDMY. We don’t need to define a line from the endpoint CDMY17CDMY to the initial CDMY18CDMY, it will be drawn by default.

The result can be seen in figure (b) with a pink triangle.

@override Path getClip(Size size) { Path path=Path() ..lineTo(0, size.height)//Добавить отрезок p1p2 ..lineTo(size.width, size.height)//Добавить отрезок p2p3 ..close(); return path; } 


This method is needed to move the drawing point.

ITKarma picture

As shown in the figure above, the starting point has been moved from CDMY19CDMY to point CDMY20CDMY.

@override Path getClip(Size size) { Path path=Path()//Начальная точка в (0, 0) ..moveTo(size.width/2, 0)//передвигаем точку в (width/2, 0) ..lineTo(0, size.width) ..lineTo(size.width, size.height) ..close(); return path; } 


This method is used to construct a quadratic Bezier curve.

ITKarma picture
Source: Wikipedia

As shown in the above figure, we can draw a quadratic Bezier curve using the control and end points. P0 is the start point, P1 is the breakpoint, and P2 is the end point.

ITKarma picture

As shown in figure (a) above, the curve is drawn from the point CDMY21CDMY to CDMY22CDMY using the control point CDMY23CDMY.

@override Path getClip(Size size) {//Эта переменная определена для лучшего понимания, какое значение указать в методе quadraticBezierTo var controlPoint=Offset(size.width/2, size.height/2); var endPoint=Offset(size.width, size.height); Path path=Path() ..moveTo(size.width/2, 0) ..lineTo(0, size.height) ..quadraticBezierTo( controlPoint.dx, controlPoint.dy, endPoint.dx, endPoint.dy) ..close(); return path; } 


This method is used to construct a cubic curve by specifying 2 control and end points.

ITKarma picture

The figure above is an illustration of various cubic curves with different locations of control points.

ITKarma picture

As shown in Figure (a), a cubic curve is drawn between the starting point CDMY24CDMY and the ending point CDMY25CDMY using the control points CDMY26CDMY and CDMY27CDMY.

@override Path getClip(Size size) { var controlPoint1=Offset(50, size.height - 100); var controlPoint2=Offset(size.width - 50, size.height); var endPoint=Offset(size.width, size.height - 50); Path path=Path() ..moveTo(size.width/2, 0) ..lineTo(0, size.height - 50) ..cubicTo(controlPoint1.dx, controlPoint1.dy, controlPoint2.dx, controlPoint2.dy, endPoint.dx, endPoint.dy) ..close(); return path; } 


This method is needed to draw an arc from the starting point to the specified point. We can adjust the arc by setting the radius, indicating the direction (clockwise/counterclockwise).

ITKarma picture

There are elliptical and circular radius types for constructing an arc. As shown in the above figure, an elliptical radius is drawn using the CDMY28CDMY value, and a circular radius is drawn using the CDMY29CDMY radius.

ITKarma picture

As shown in figure (a) above, the construction of the figure begins at point CDMY30CDMY. The first arc is drawn from the point CDMY31CDMY to the point CDMY32CDMY, while the radius is not specified, so the default is zero , so our arc looks like a straight line. The second arc extends from the starting point CDMY33CDMY to the ending point CDMY34CDMY using a circular radius and clockwise direction (approx. Clockwise - default direction) . The third arc extends from point CDMY35CDMY to point CDMY36CDMY, using a circular radius and counterclockwise direction. The fourth arc extends from the starting point CDMY37CDMY to the ending point CDMY38CDMY using an elliptical radius.

@override Path getClip(Size size) { double radius=20; Path path=Path() ..moveTo(radius, 0) ..lineTo(size.width-radius, 0) ..arcToPoint(Offset(size.width, radius)) ..lineTo(size.width, size.height - radius) ..arcToPoint(Offset(size.width - radius, size.height),radius: Radius.circular(radius)) ..lineTo(radius, size.height) ..arcToPoint(Offset(0, size.height - radius), radius: Radius.circular(radius), clockwise: false) ..lineTo(0, radius) ..arcToPoint(Offset(radius, 0), radius: Radius.elliptical(40, 20)) ..close(); return path; } 


This method is used to draw an arc by setting radians Rect , start angle (startAngle) and end angle (sweepAngle).

ITKarma picture

The above image is intended to provide basic information about angles in radians. The minimum angle is 0 PI (PI value is ~ 3.14), the full angle is 2 PI.

ITKarma picture

There are several ways to build a Rect , such as using points, circles, LTRB (Left, Top, Right, Bottom) and LTWH (Left, Top, Width, Height). In the above figure (a), all types of arcs are drawn with different starting angles.

@override Path getClip(Size size) { double radius=50; Path path=Path() ..lineTo(size.width - radius, 0) ..arcTo( Rect.fromPoints( Offset(size.width - radius, 0), Offset(size.width, radius)),//Rect 1.5 * pi,//начальный угол 0.5 * pi,//конечный угол true)//направление по часовой стрелке ..lineTo(size.width, size.height - radius) ..arcTo(Rect.fromCircle(center: Offset(size.width - radius, size.height - radius), radius: radius), 0, 0.5 * pi, false) ..lineTo(radius, size.height) ..arcTo(Rect.fromLTRB(0, size.height - radius, radius, size.height), 0.5 * pi, 0.5 * pi, false) ..lineTo(0, radius) ..arcTo(Rect.fromLTWH(0, 0, 70, 100), 1 * pi, 0.5 * pi, false) ..close(); return path; } 


This method is needed to build rectangles. There are several different methods for creating CDMY39CDMY: CDMY40CDMY, CDMY41CDMY, CDMY42CDMY, CDMY43CDMY and CDMY44CDMY.

ITKarma picture

@override Path getClip(Size size) { Path path=Path() ..addRect(Rect.fromPoints(Offset(0, 0), Offset(60, 60))) ..addRect(Rect.fromLTWH(0, size.height - 50, 50, 50)) ..addRect(Rect.fromCircle(center: Offset(size.width/2, size.height/2), radius: 20)) ..close(); return path; } 


This method is used to add a rounded rectangle. You can round, as all corners at once, and one.

ITKarma picture

@override Path getClip(Size size) { double radius=10; Path path=Path() ..addRRect(RRect.fromLTRBR(0, 0, 60, 60, Radius.circular(radius))) ..addRRect(RRect.fromRectAndRadius( Rect.fromLTWH(0, size.height - 50, 50, 50), Radius.circular(radius))) ..addRRect(RRect.fromRectAndCorners( Rect.fromCircle( center: Offset(size.width/2, size.height/2), radius: 30 ), topLeft: Radius.circular(radius))) ..close(); return path; } 


This method is used to describe the oval. As with CDMY45CDMY, a parameter of type CDMY46CDMY is required.

ITKarma picture

@override Path getClip(Size size) { Path path=Path() ..addOval(Rect.fromPoints(Offset(0, 0), Offset(60, 60))) ..addOval(Rect.fromLTWH(0, size.height - 50, 100, 50)) ..addOval(Rect.fromCircle(center: Offset(size.width/2, size.height/2), radius: 20)) ..close(); return path; } 


This method is used to add a polygon by defining multiple points.

ITKarma picture

@override Path getClip(Size size) { var points=[ Offset(size.width/2, 0),//точка p1 Offset(0, size.height/2),//точка p2 Offset(size.width/2, size.height),//точка p3 Offset(size.width, size.height/2)//точка p4 ]; Path path=Path() ..addPolygon(points, false) ..close(); return path; } 


This method is useful if you need to add another shape to the display to the existing one. To do this, specify the description of the figure and the shift relative to the starting position of the point for calculating the coordinates of the new figure.

ITKarma picture

As shown in Figure (a), there are two figures (CDMY47CDMY and CDMY48CDMY), CDMY49CDMY is the main one, and CDMY50CDMY is added to CDMY51CDMY. CDMY52CDMY is constructed in accordance with the shift CDMY53CDMY, so the origin of coordinates CDMY54CDMY and all other points are calculated taking into account the specified offset.

@override Path getClip(Size size) { Path path1=Path() ..lineTo(0, size.height) ..lineTo(size.width/2, size.height) ..lineTo(0, 0); Path path2=Path() ..lineTo(size.width/2, size.height) ..lineTo(size.width/2, 0) ..lineTo(0, 0); path1.addPath(path2, Offset(size.width/2,0)); return path1; } 


This method is similar to the CDMY55CDMY method, but the end point of the line is set not by the exact coordinate, but by the offset from the start.

ITKarma picture

In Figure (a), the CDMY56CDMY line is drawn using CDMY57CDMY, so the coordinate of the point CDMY58CDMY is calculated relative to CDMY59CDMY. Can be written as a formula CDMY60CDMY

@override Path getClip(Size size) { Path path=Path() ..moveTo(size.width/2, 0) ..relativeLineTo(50, size.height) ..lineTo(size.width, size.height) ..close(); return path; } 

Note: CDMY61CDMY, CDMY62CDMY, CDMY63CDMY, CDMY64CDMY will work compared to CDMY65CDMY, CDMY66CDMY, CDMY67CDMY by the same principle as CDMY68CDMY with respect to MGKM83>MGKM83.

I hope that this material will be useful to you and help you create new cool shapes.