After the previous post about drawing a custom CircleProgressBar with CustomPaint, today I’m going to share a few basics of custom Views (CustomPaint)

The canvas canvas

A canvas is a rectangular area where we can control every pixel to draw what we want

Canvas has a variety of ways to draw points, lines, paths, rectangles, circles, and add images. Combined with these methods, we can draw an ever-changing picture.

Although the canvas can draw these things, it is the brush that determines the color, thickness, and presentation of these shapes.

Brush Paint

Paint is the tool we use to draw shapes. We can set the color, thickness, anti-aliasing, shape, and style of the brush.

With these properties we can easily customize our UI effects, of course we can define more than one brush in the process of “drawing”, which makes it easier for us to draw the graphics

Properties for the brush Paint

Canvas has several methods related to drawing, such as drawLine(), drawRect(), drawOval(), drawOval(), and so on.

However, canvas alone is not enough. We also need a paint. We can use the following code to build the paint

Paint _paint = Paint() .. Color = Colors. BlueAccent // StrokeCap = strokecap. round // Brush type.. IsAntiAlias = true // Whether to enable anti-aliasing.. BlendMode = BlendMode.Exclusion // Color blending mode.. Style = paintingstyle. fill // ColorFilter = colorFilter. mode(color.blueaccent, blendmode.Exclusion) colorFilter = ColorFilter.mode(color.blueaccent, blendmode.Exclusion) colorFilter = ColorFilter.mode(color.blueaccent, blendmode.Exclusion) MaskFilter = maskFilter. Blur (blurstyle.inner, 3.0) FilterQuality = filterQuality. High // Color rendering mode quality.. StrokeWidth = 15.0; // The width of the brushCopy the code

Of course, in normal development will not generally use so many attributes, you can according to the need to specific understanding and use.

The canvas method canvas

The following is drawn based on this brush:

Paint _paint = new Paint() .. color = Colors.blueAccent .. strokeCap = StrokeCap.round .. isAntiAlias = true .. StrokeWidth = 5.0.. style = PaintingStyle.stroke;Copy the code

Draw a straight line

void drawLine(Offset p1, Offset p2, Paint paint)

Draws a line between given points using the given paint. The line is stroked, this call ignores the value of [paint. style]. P1 and P2 take the coordinates of the two points, and draw a line between them.

Eg: Canvas. DrawLine (Offset(20.0, 20.0), Offset(100.0, 100.0), _paint)Copy the code

Draw some drawPoints

void drawPoints(PointMode pointMode, List points, Paint paint)

The PointMode enumeration has three types: points, lines, and polygon.

Canvas. DrawPoints (///PointMode has three enumerated types: points, lines, polygon, Pointmode. points, [Offset(20.0, 130.0), Offset(100.0, 210.0), Offset(100.0, 310.0), Offset (200.0, 210.0), the Offset (280.0, 130.0), Offset (20.0, 130.0),], _paint.. color = Colors.redAccent);Copy the code

For the sake of illustration, we have defined seven points above, the first and the last point overlap.

Then let’s set PointMode to points and see what happens.

Then we change PointMode to lines

When PointMode is lines, the two points are connected to each other, that is, the first point is connected to the second point, the third point is connected to the fourth point, and if there is only one point in the end, the connection is abandoned. In our example, there are seven points, so there are only three lines in the diagram.

Then we change PointMode to lines

Yeah, you’re seeing exactly the same thing as when I drew the line segment above, where the adjacent points are connected to each other.

Draw round rawCircle

void drawCircle(Offset c, double radius, Paint paint)

The parameters are: center coordinates, radius, and paint. Whether the circle is filled or stroked (or both) is controlled by paint.style.

Canvas. DrawCircle (Offset(100.0, 350.0), 30.0, _paint.. color = Colors.greenAccent .. Style = paintingstyle. stroke //Copy the code

So in this case I’m changing the style of the Paint to stroke and then we’re changing the style of the brush to fill, which is also the default for the style of the brush.Once filled, the circle becomes solid.

Draw the ellipse drawOval

void drawOval(Rect rect, Paint paint)

Draw an axisymmetric ellipse as a rectangle and brush paint.

Rect rect1 = rect.frompoints (Offset(150.0, 200.0), Offset(300.0, 250.0)); canvas.drawOval(rect1, _paint);Copy the code

We’ve already seen how Rect is used to determine the size and position of the rectangle.

Rect can also be built in several ways:

FromCircle ({Offset center, Offset center, Offset center, Offset center, Double radius}) use the center coordinates and radius of the circle and determine the size and position of the outer rectangle fromLTRB(double left, double top, double right, FromLTWH (double left, double top, double width, double left, double top, double width, double left) Double height) Determine the size and position of the rectangle using the X coordinates to the left of the rectangle and the Y coordinates at the top of the rectangleCopy the code

Draw the arc drawArc

void drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint)

First, you need to Rect to confirm the arc’s position, the beginning radian, the end radian, whether the arc is drawn with a center point (whether the arc is closed toward the center), and paint.

radian

According to the definition, the number of radians in a week is 2 PI r/r=2 PI, 360° Angle =2 PI radian, so 1 radian is about 57.3°, that is, 57°17 ‘44.806’, 1° is PI /180 radian, the approximation is 0.01745 radian, the circumference is 2 PI radian, the flat Angle (i.e. the 180° Angle) is PI radian, and the right Angle is PI /2 radian.

Special radians:
The degree of radian
0 ° 0
30 ° PI / 6
45 ° PI / 4
60 ° PI / 3
90 ° PI / 2,
120 ° 2 PI / 3
180 ° PI.
270 ° 3 PI / 2
360 ° 2 PI.
Rect rect2 = rect.fromcircle (center: center) Rect = rect.fromcircle (center: center) Offset (200.0, 50.0), the radius, 80.0); Canvas. DrawArc (rect2, 0.0, 0.8, false, _paint);Copy the code

Draw a 90 degree radian

Const PI = 3.1415926; Rect rect2 = rect.fromcircle (center: Offset(200.0, 50.0), radius: 80.0); Canvas. DrawArc (rect2, 0.0, PI / 2, false, _paint);Copy the code

Define PI as 3.1415926, start at 0°, sweep at PI / 2 (90°), and set userCenter to falseTry changing useCenter to true:We find that the arc closes toward the center point.

Draw the drawDRRect rectangle with rounded corners

void drawRRect(RRect rrect, Paint paint)

Use RRect to determine the size and radian of the rectangle, and use Paint to complete the drawing.

RRect is also very easy to build, just use fromRectAndRadius

RRect.fromRectAndRadius(rect, radius)

Rect is still used to indicate the position and size of the rectangle, and RADIUS is used to indicate the size of the rounded corners.

Rect Rect = rect.fromCircle (center: Offset(100.0, 150.0), radius: 50.0); RRect RRect = rrect.fromRectandRADIUS (rect, radius.circular (20.0)); canvas.drawRRect(rrect, _paint);Copy the code

Set the radius of the fillet to the side length (from 20 to 50) and try this:It becomes a circle.

Draws a double rounded rectangle drawRRect

void drawDRRect(RRect outer, RRect inner, Paint paint)

Similar to drawRRect, use RRect to determine the size and radian of the inner and outer rectangles, and use Paint to complete the drawing.

Rect rect1 = rect.fromcircle (center: Offset(100.0, 100.0), radius: 60.0); Rect rect1 = rect.fromcircle (center: Offset(100.0, 100.0), radius: 60.0); Rect rect2 = rect.fromcircle (center: Offset(100.0, 100.0), radius: 40.0); RRect outer = rrect.fromrectandRADIUS (rect1, radius.circular (10.0)); RRect outer = rrect.fromrectandRADIUS (rect1, Radius. RRect inner = rrect.fromrectandRADIUS (rect2, radius.circular (10.0)); canvas.drawDRRect(outer, inner, _paint);Copy the code

Use rect.fromCircle to create rects and rrect.fromRectandRADIUS to create rRects

We can see two rectangles with rounded corners, but we can also try to adjust the Angle.

Rect rect1 = rect.fromcircle (center: Offset(100.0, 100.0), radius: 60.0); Rect rect1 = rect.fromcircle (center: Offset(100.0, 100.0), radius: 60.0); Rect rect2 = rect.fromcircle (center: Offset(100.0, 100.0), radius: 40.0); RRect outer = rrect.fromrectandRADIUS (rect1, radius.circular (30.0)); RRect outer = rrect.fromrectandRADIUS (rect1, Radius. RRect inner = rrect.fromrectandRADIUS (rect2, radius.circular (5.0)); canvas.drawDRRect(outer, inner, _paint);Copy the code

You can even adjust the size of the Angle so that both rectangles become circles to form a circle.

DrawPath drawPath

void drawPath(Path path, Paint paint)

To draw a path, you first need a path to draw, and then the paint.

Common methods for Path:

The method name role
moveTo Moves the starting point of the path to the specified location
relativeMoveTo Moves to relative to the current position
lineTo Connects the specified point from the current location
relativeLineTo Connected to relative to the current location
arcTo curve
conicTo Bessel curve
add** To add other graphics, such as addArc, the path is to add arcs
contains Whether the path includes a point
transfor Perform a Matrix4 transformation for the path
combine Combine the two paths
close Close the path and connect the starting point of the path
reset Reset the path to the default state

eg:

// Create a new path and move the starting point of the path to the coordinate (100,100). MoveTo (100.0, 100.0); Path. The lineTo (200.0, 200.0); canvas.drawPath(path, _paint);Copy the code

First create a new path, then move the starting point of the path to the coordinate (100,100), and then connect the points (200,200) from this position.

We can also draw multiple paths:

Path path = new Path().. MoveTo (100.0, 100.0); Path. The lineTo (200.0, 200.0); Path. The lineTo (100.0, 300.0); Path. The lineTo (150.0, 350.0); Path. The lineTo (150.0, 500.0); canvas.drawPath(path, _paint);Copy the code

Use second order Bezier curves to draw arcs:

void arcTo(Rect rect, double startAngle, double sweepAngle, bool forceMoveTo)

Rect, as we know, is a rectangle,startAngle is the beginning radian,sweepAngle is the end radian

  • If the “forceMoveTo” parameter is false, a line segment and an arc segment are added.
  • If the “forceMoveTo” parameter is true, a new subpath is started that contains an arc.

Such as:

Path path = new Path().. MoveTo (100.0, 100.0); Rect Rect = rect.fromcircle (center: Offset(200.0, 200.0), radius: 60.0); Path. ArcTo (the rect, 0.0, 3.14, false); canvas.drawPath(path, _paint);Copy the code

Here, we draw a semicircle using the Bezier curve, because the starting point is (100,100), and when we draw the Bezier curve, the origin of the curve is (200,200) radius 60, so we move to (200,260) and then we draw the curve.

Since forceMoveTo is false, we draw a straight path from the starting point to the starting point of the curve. If forceMoveTo is true, we can see that the line segment is missing because a new subpath is started:

Of course, you can even draw a circle directly using bezier curves:

Rect Rect = rect.fromcircle (center: Offset(200.0, 200.0), radius: 60.0); Path. ArcTo (the rect, 0.0, 3.14 * 2, false); canvas.drawPath(path, _paint);Copy the code

Draw ❤ using third-order Bezier curves:

void cubicTo(double x1, double y1, double x2, double y2, double x3, double y3)

    var width = 200;
    var height = 300;
    path.moveTo(width / 2, height / 4);
    path.cubicTo((width * 6) / 7, height / 9, (width * 13) / 13,
        (height * 2) / 5, width / 2, (height * 7) / 12);
    canvas.drawPath(path, _paint);

    Path path2 = new Path();
    path2.moveTo(width / 2, height / 4);
    path2.cubicTo(width / 7, height / 9, width / 21, (height * 2) / 5,
        width / 2, (height * 7) / 12);
    canvas.drawPath(path2, _paint);
Copy the code

Look at the effect:

Then we change the paint style:

canvas.drawPath(path, _paint); Canvas. DrawPath (path, _paint.. style = PaintingStyle.fill .. color = Colors.red);Copy the code

Let’s change the color of the brush to red and change the style to Fill:

DrawColor drawColor

void drawColor(Color color, BlendMode blendMode)

Let’s draw a circle:

Canvas. Methods like drawCircle (Offset (100.0, 100.0), 50.0, _paint);Copy the code

Then we add a line of code:

Canvas. Methods like drawCircle (Offset (100.0, 100.0), 50.0, _paint); canvas.drawColor(Colors.red, BlendMode.color); // Add this rowCopy the code

As you can see, the color of the circle has changed to red. We can also change the BlendMode, for example: BlendMode.colorDodge More effects can be found in the BlendMode source code.

DrawImage drawImage

void drawImage(Image image, Offset p, Paint paint)

To draw a given image to the canvas with its upper left corner offset, we first need to get the local image file and then draw the image

The full text of the code has been submitted to Github