Starting today, HenCoder is officially talking about knowledge and skills. According to my plan, the first season is UI, which is divided into three parts: drawing, layout, and touch feedback. This is the first installment of the drawing section. Drawing will take about 5-6 sessions, and the entire UI drawing, layout, and touch feedback will take about 10 sessions. Update frequency is approximately every Monday (no commitment).

If you don’t know what HenCoder is, take a look at this:

HenCoder: An advanced manual for advanced Android engineers

Overview of custom drawing

Without saying a word, MY backhand is a video: (video hang up, first direct point to youku to see: Youku link)

To summarize the key points from the video:

  • Custom drawing is done by overriding drawing methods, the most common of which is onDraw()
  • The key to drawing is the use of Canvas
    • DrawXXX () (key: Paint)
    • Canvas auxiliary class methods: range clipping and geometry transformation
  • Shading relationships can be controlled using different rendering methods

I’ve covered it all in the video, and it’s not a lot of information, but as you can see, I’m not going into detail. This is because although there are not many knowledge points, but there are still many details, just by sharing a section can not be finished. I have divided this knowledge into four levels in order and broken it down into several sections. If you follow the four levels in order, you will be able to make smooth progress.

Four levels of custom drawing knowledge

  1. Canvas’s drawXXX() family of methods and Paint are most commonly used

    Canvas.drawxxx () is the most basic operation for custom drawing. After mastering these methods, you will know how to draw content, such as circles, squares, images and text. Combining this with some of the common methods of Paint to simply configure the color and style of the content to be painted should cover most of your drawing requirements.

    That’s what I’m going to talk about in today’s post. In other words, after you have read the passage and done the exercises, you should be able to draw the pictures above. From now on, you’ll rarely have to say, “No, that’s not technically possible” to a designer, or wait in trepidation for a designer to say, “How can iOS?”

  2. Paint’s complete walkthrough

    Paint can do more than just set colors, it can do more than what I talked about in videos like solid and hollow, line thickness, shadow or not, it can do a lot more, a lot more. Such as:

    What shape do you want for the corner?

    Can you turn on bilinear filtering?

    Special effects or not?

There are so many that can be adjusted, I’m not going to list them all. When you get to this level, there really isn’t anything that iOS can do that you can’t do. Even if the designers come up with something that’s hard to do, it’s not going to be your Android team that can’t do it.

  1. Canvas aid for drawing – range cutting and geometry transformation.

    Range cutting:

    Geometric transformation:

    Most of the time, they’re not used, but when they are, they’re usually pretty cool. Range clipping and geometry transformations are ancillary, they are not cool in themselves, what makes them cool is the imagination and creativity of the designers. What you have to do is take their imagination and creativity and turn it into reality.

  2. Use different drawing methods to control the drawing order

    Controlling the drawing order solves not the “can’t do” problem, but the performance problem. You can often do the same thing without having to control the drawing order, but it takes multiple views or even multiple views to piece together, so it costs UI performance; With the draw order control, one View is done.

The knowledge of custom drawing is roughly divided into the above four levels. After you have mastered these four levels in turn, you are a master of custom drawing. I’ll break them down into several chapters. This is the first article on the canvas.drawxxx () family of methods and the basic use of Paint. Shall I officially get started?

Where it all begins: onDraw()

Getting started with custom drawing is easy: create a Paint object in advance, override onDraw(), and put the code inside onDraw(). Something like this:

Paint paint = new Paint();

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    // Draw a circle
    canvas.drawCircle(300.300.200, paint);
}Copy the code

It’s that simple. So there’s really nothing to say about onDraw(), a very common method to override, the only thing to be careful about is super.ondraw ().

Canvas.drawxxx () and Paint basics

Once you’ve mastered the basics of the drawXXX() family of methods and Paint, you can handle simple drawing needs. They mainly include:

  1. CanvasClassdraw-The way to start, for exampledrawCircle() drawBitmap().
  2. PaintClass. Concrete is:
    • Paint.setStyle(Style style)Set the drawing mode
    • Paint.setColor(int color)Set the color
    • Paint.setStrokeWidth(float width)Set line width
    • Paint.setTextSize(float textSize)Setting text size
    • Paint.setAntiAlias(boolean aa)Set the anti-aliasing switch

For those of you who are more self-taught (and I am), you can go to the Official Google documentation, open the Canvas and Paint pages, and learn about these two methods, and then we’re done for today. Of course, this article can also be turned off.

The following sections expand on these two methods.

Canvas. DrawColor (@colorint int color) Color fill

This is the most basic drawXXX() method: paint the entire drawing area with the specified color.

For example, drawColor(color.black) will Color the entire area pure BLACK, covering the original content; DrawColor (color.parse (“#88880000”) will add a translucent red mask to the original drawing.

drawColor(Color.BLACK);  / / pure blackCopy the code

drawColor(Color.parse("# 88880000"); // Translucent redCopy the code

DrawRGB (int r, int g, int b) drawARGB(int a, int R, int g, int B) drawRGB(int a, int R, int G, int B) drawARGB(int a, int R, int G, int B)

canvas.drawRGB(100.200.100);
canvas.drawARGB(100.100.200.100);Copy the code

These color filling methods are commonly used to set the background color before drawing, or to set a translucent mask for the interface after drawing.

DrawCircle (float centerX, float centerY, float radius, Paint Paint

The first two parameters centerX centerY are the coordinates of the center of the circle, and the third parameter radius is the radius of the circle, both in pixels. Together, they constitute the basic information of the circle. The fourth parameter paint, which I’ve covered in the video, provides all the style information beyond the basic information, such as color, line thickness, shadows, and so on.

canvas.drawCircle(300.300.200, paint);Copy the code

The guy said, “Wait a minute! Don’t talk back, you just said the coordinates of the center of the circle, I want to ask where the coordinate system is? Without the coordinate system, you can’t talk to me about coordinates.”

I want to say: Good question. In Android, each View has its own coordinate system, which does not affect each other. The origin of this frame is that point in the upper left corner of View; The horizontal direction is X-axis, positive on the right and negative on the left; The vertical direction is the Y-axis, plus down and minus up. So it’s going to look like this.

So a View’s coordinates (x, y) are x pixels horizontally and y pixels vertically relative to the point in its upper left corner. For example, (300, 300) refers to the point in the upper left corner that is 300 to the right and 300 down; (100, -50) is the point in the upper left corner 100 to the right and 50 up.

DrawCircle (300, 300, 200, paint); drawCircle(300, 300, 200, paint);

The coordinates of the center of the circle and the radius, these are the basic information of the circle, but also its unique information. What is unique information? It’s information that only it has and no one else has. When you draw a circle, you have the center coordinates and the radius, do you have the square? Do you have ellipses? This is called unique information. Unique information is written directly into the drawXXX() method as arguments (such as the first three arguments of drawCircle(centerX, centerY, RADIUS, paint).

Beyond that, everything else is public information. Things like the color of the shape and the hollow solid, which you can use to draw circles or squares, are included in the paint parameters.

SetColor (int color)

For example, if you want to draw a RED circle, instead of writing it as canvas.drawCircle(300, 300, 200, RED, paint), it would look like this:

paint.setColor(Color.RED); // Set it to red
canvas.drawCircle(300.300.200, paint);Copy the code

SetColor (int color) is one of the most common methods of Paint, used to set the color of the content to be drawn. You can draw not only red circles with it, but also red rectangles, red stars, red text.

SetStyle (Paint.Style Style)

If you want to draw hollow circles (or circles) instead of solid circles, you can also use paint.setstyle (paint.style.stroke) to change your drawing mode to line mode.

paint.setStyle(Paint.Style.STROKE); // Change the Style to line mode
canvas.drawCircle(300.300.200, paint);Copy the code

SetStyle (Style Style) This method sets the Style of the drawing. Specifically, there are three styles: FILL, STROKE and FILL_AND_STROKE. FILL is the FILL mode, STROKE is the line mode, and FILL_AND_STROKE is both the line and FILL mode. Its default value is FILL, FILL mode.

Paint. SetStrokeWidth (float width)

Under STROKE and FILL_AND_STROKE, you can also use paint.setstrokeWidth (float width) to set the width of the line:

paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(20); // The line width is 20 pixels
canvas.drawCircle(300.300.200, paint);Copy the code

Insert 4: Anti-aliasing

When drawing, it is often necessary to enable anti-aliasing to smooth the edges of graphics and text. Turning on anti-aliasing is as simple as adding an ANTI_ALIAS_FLAG parameter to new Paint() :

Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);Copy the code

Alternatively, you can use paint.setantiAlias (Boolean aa) to dynamically switch anti-aliasing on or off.

The anti-aliasing effects are as follows:

It can be seen that when anti-aliasing is not enabled, the graphics will have the phenomenon of rough, ah no, rough. So be sure to turn on anti-aliasing!

Trivia that can be skipped

Curious people might ask: since anti-aliasing is so useful, why not turn it on by default, or turn it off, and automatically turn it on for all drawings?

Short answer: Because anti-aliasing is not necessarily appropriate for all scenarios.

Long answer: The so-called burrs or jagged edges are not caused by “rough drawing” or “insufficient pixel computing power” as many people imagine. Similarly, the principle of anti-aliasing is not to choose a finer algorithm to produce smoother edges. In essence, the sawtooth phenomenon occurs when the resolution of the image is too low, causing the human eye to detect the pixel particles in the image. In other words, the edges of the graph are as good as they can be without anti-aliasing, not a rough version of a rough calculation. So why does anti-aliasing make edges smoother? The principle of anti-aliasing is to change the color of the pixels at the edges of the graphics so that the graphics look smoother to the naked eye. A picture is worth a thousand words, above:


The top one is a partial view of the first two circles zoomed in. See? Circles without anti-aliasing are the same black color for all pixels, while circles with anti-aliasing on have their edges slightly changed. This change makes the edges appear smooth to the human eye, but in some ways it also distorts the color of the image.


So, how about anti-aliasing? Well, it should be on most of the time; But there are rare occasions when you actually need to turn it off. When is “some time”? You’ll know when you use it.

Besides circles, Canvas can also draw some other simple graphics. They are used in much the same way as drawCircle(), so I’ll just go through their apis without going into the details.

DrawRect (float left, float top, float right, float bottom, Paint Paint

Left, top, right, bottom are the coordinates of the four sides of the rectangle.

paint.setStyle(Style.FILL);
canvas.drawRect(100.100.500.500, paint);

paint.setStyle(Style.STROKE);
canvas.drawRect(700.100.1100.500, paint);Copy the code

In addition, it has two overloaded methods drawRect(RectF Rect, Paint Paint) and drawRect(Rect Rect, Paint Paint), which let you directly fill in RectF or Rect objects to draw rectangles.

DrawPoint (float x, float y, Paint Paint

X and y are the coordinates of points. The point size can be set using paint.setstrokeWidth (width); The shape of the points can be set with paint.setstrokecap (cap) : ROUND is drawn as a ROUND point, and SQUARE or BUTT is drawn as a SQUARE point. (Dots and shapes? Yes, that’s what Google says anyway. Ask Google, and I’m confused.)

Note: Paint.setstrokecap (CAP) can set the shape of a point, but this method is not used to set the shape of a point. It is a method to set the shape of the end of a line. There are three types of end points: ROUND, BUTT, and SQUARE, which we’ll talk about in the next section.

paint.setStrokeWidth(20);
paint.setStrokeCap(Paint.Cap.ROUND);
canvas.drawPoint(50.50, paint);Copy the code

paint.setStrokeWidth(20);
paint.setStrokeCap(Paint.Cap.SQUARE;
canvas.drawPoint(50.50, paint);Copy the code

It’s kind of like drawCircle() and drawRect() in FILL mode, right? In fact, they are exactly the same as drawPoint(). Everyone in the use of the time according to personal habits and actual scene, which convenient and handy to use which.

DrawPoints (float[] PTS, int offset, int count, Paint Paint)/drawPoints(float[] PTS, Paint Paint)

It’s the same thing as drawPoint, but the difference is that you can draw multiple points. The PTS array is the coordinates of points, two in pairs; Offset means to skip the first few numbers of the array and start remembering coordinates. Count means how many points to draw. You may get dizzy by reading so much, but try it yourself. This is a simple way to look complicated.

float[] points = {0.0.50.50.50.100.100.50.100.100.150.50.150.100};
// draw four points :(50, 50) (50, 100) (100, 50) (100, 100)
canvas.drawPoints(points, 2 /* Skip two numbers, the first two zeros */.8 /* Draw a total of 8 numbers (4 points) */, paint);Copy the code

DrawOval (float left, float top, float right, float bottom, Paint Paint) draws ellipses

Only horizontal or vertical ellipses can be drawn, not oblique ones (oblique ones can be drawn, but not directly using drawOval(), but in conjunction with geometric transformations, as described below). Left, top, right, bottom are the coordinates of the four boundary points of the ellipse.

paint.setStyle(Style.FILL);
canvas.drawOval(50.50.350.200, paint);

paint.setStyle(Style.STROKE);
canvas.drawOval(400.50.700.200, paint);Copy the code

In addition, it has an overloaded drawOval(RectF rect, Paint Paint) method that allows you to draw ellipses directly by filling in RectF.

DrawLine (float startX, float startY, float stopX, float stopY, Paint Paint

StartX, startY, stopX, stopY are the starting and ending coordinates of the line respectively.

canvas.drawLine(200.200.800.500, paint);Copy the code

Since a line is not a closed graph, setStyle(style) has no effect on the line.

DrawLines (float[] PTS, int offset, int count, Paint Paint)/drawLines(float[] PTS, Paint Paint)

DrawLines () is the plural version of drawLine().

float[] points = {20.20.120.20.70.20.70.120.20.120.120.120.150.20.250.20.150.20.150.120.250.20.250.120.150.120.250.120};
canvas.drawLines(points, paint);Copy the code

Oh, accidentally typed two Chinese characters. — Is it Chinese characters?

DrawRoundRect (float left, float top, float right, float bottom, float Rx, float RY, Paint Paint) draws rounded rectangles

Left, top, right, bottom are the coordinates of the four edges, and rx and ry are the transverse and longitudinal radii of the rounded corners.

canvas.drawRoundRect(100.100.500.300.50.50, paint);Copy the code

In addition, it has an overloaded drawRoundRect(RectF Rect, float rx, float RY, Paint Paint) method that lets you fill in RectF directly to draw rounded rectangles.

drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint Paint) draw arcs or fans

DrawArc () uses an ellipse to describe arcs. Left, top, right, bottom describe the ellipse where the arc is; StartAngle is the starting Angle of the arc (the positive x axis, that is, the direction to the right, is 0 degrees; Clockwise is a positive Angle, anticlockwise is a negative Angle), sweepAngle is the Angle of arc passing; The useCenter indicates whether it’s connected to the center of the circle, if it’s not, it’s an arc, if it’s connected to the center, it’s a sector.

paint.setStyle(Paint.Style.FILL); // Fill mode
canvas.drawArc(200.100.800.500, -110.100.true, paint); // Draw the fan
canvas.drawArc(200.100.800.500.20.140.false, paint); // Draw an arc
paint.setStyle(Paint.Style.STROKE); // Line mode
canvas.drawArc(200.100.800.500.180.60.false, paint); // Draw an unsealed arcCopy the code

So far, this is all about drawing simple graphics on Canvas. Besides drawing simple graphics, Canvas can also use drawPath(Path Path) to draw custom graphics.

DrawPath (Path Path, Paint Paint) Draws a custom graph

This method is a little complicated and needs to be expanded.

Whereas the previous methods draw a given graph, drawPath() can draw a custom graph. You can use drawPath() when you want to draw something special that is not possible using the previous methods.

DrawPath (path) This method draws a graph by describing a path, and its path parameter is the object used to describe the graph path. Path is of type path and can be used as follows:

public class PathView extends View {

    Paint paint = new Paint();
    Path path = new Path(); // Initialize the Path object. {// Use path to describe the graph.
      path.addArc(200.200.400.400, -225.225);
      path.arcTo(400.200.600.400, -180.225.false);
      path.lineTo(400.542);
    }

    @Override
    protected void onDraw(Canvas canvas) {
      super.onDraw(canvas);

      canvas.drawPath(path, paint); // Draw the shape described by path (heart) and you are done}}Copy the code

Path can describe straight lines, conics, cubic curves, circles, ellipses, arcs, rectangles, and rounded rectangles. By combining these figures, many complex figures can be described. So I’m going to show you exactly how to represent these figures.

Path has two classes of methods: those that describe paths directly and those that assist in setting or calculating them.

The first type of Path method: describes a Path directly.

This class of methods can be subdivided into two groups: adding subshapes and drawing lines (lines or curves)

The first group:addXxx()Add child graphics
AddCircle (float x, float y, float radius, Direction dir) adds a circle

The x, y, and radius parameters are the basic information about the circle. The last parameter dir is the direction of the path to draw the circle.

There are two paths that are CLOCKWISE (CW) and counter-clockwise (CCW counter-clockwise). For the ordinary case, it makes no difference whether this parameter is filled with CW or CCW. It is only used to determine the FILL range when a shape (Paint.Style is FILL or FILL_AND_STROKE) needs to be filled and the shape appears self-intersecting. For example, here’s a graph:

Should it be filled like this:

Or should it be filled like this:

It’s up to you to fill it any way you want. I’ll explain how to do this in more detail when I talk about path.setfilltype (), but here you can ignore dir.

After adding a circle to Path with addCircle(), call Canvas. drawPath(Path, paint) to draw a circle. Something like this:

path.addCircle(300.300.200, Path.Direction.CW); . canvas.drawPath(path, paint);Copy the code

AddCircle(x, y, radius, dir) + Canvas. DrawPath (path, paint) DrawCircle (x, y, RADIUS, paint) has the same effect as using Canvas. DrawCircle (x, y, RADIUS, paint), but it’s more complicated to write. So if you’re just drawing a circle, you don’t have to use Path, you just drawCircle(). DrawPath () is usually used when drawing composite graphics.

Other path.add -() methods are similar, for example:

AddOval (float left, float top, float right, float bottom, Direction dir)/addOval(RectF oval, Direction dir
AddRect (float left, float top, float right, float bottom, Direction dir)/addRect(RectF rect, Direction dir) adds a rectangle
addRoundRect(RectF rect, float rx, float ry, Direction dir) / addRoundRect(float left, float top, float right, float bottom, float rx, float ry, Direction dir) / addRoundRect(RectF rect, float[] radii, Direction dir)/addRoundRect(float left, float top, float right, float bottom, float[] radii, Direction dir) add rounded rectangle
AddPath (Path Path) Adds another Path

These methods are similar to addCircle(), so I won’t go into too much detail.

The second group:xxxTo()— Draw lines (straight lines or curves)

The difference between this group and the first group of addXxx() methods is that the first group adds the entire closed graph (except addPath()), while this group adds only a line.

LineTo(float x, float y)/rLineTo(float x, float y) Draw straight lines

Draw a line from the current position to the target position, where x and y are the coordinates of the target position. The difference between the two methods is that the lineTo(x, y) argument is an absolute coordinate, while the rLineTo(x, y) argument is a relative coordinate relative to the current position.

Current position: The current position is the end point of the method that drew Path when it was last called. The initial value is the origin (0, 0).

paint.setStyle(Style.STROKE);
path.lineTo(100.100); // Draw a line from the current position (0, 0) to (100, 100)
path.rLineTo(100.0); // Draw a line 100 pixels straight to the right from the current position (100, 100)Copy the code

QuadTo(float x1, float y1, float x2, float y2)/rQuadTo(float dx1, float dy1, float dx2, float dy2) Draw the quadratic Bezier curve

The starting point of this quadratic Bezier curve is the current position, and the parameters x1, y1, x2, y2 are the coordinates of the control point and the end point, respectively. In the same way as rLineTo(x, y), the parameters of rQuadTo(dx1, dy1, dx2, dy2) are relative coordinates

Bezier curve: A Bezier curve is a geometric curve. It describes a curve by starting point, control point and end point, mainly used in computer graphics. Concept is always easier said than heard, in short, it can draw a lot of round and beautiful graphics, but to master it, flexible use is not easy. The good news is that bezier curves aren’t very useful in general, and are only used for special shapes in a few scenarios, so if you haven’t mastered custom drawing, you can save bezier curves for later. As for how to learn it, there’s a lot of information on bezier curves that I won’t talk about here.

cubicTo(float x1, float y1, float x2, float y2, float x3, float y3) / rCubicTo(float x1, float y1, float x2, float y2, Float x3, float y3) draw the Bezier curve three times

CubicTo() and rCubicTo() are cubic Bessel curves in the same way as quadTo() and rQuadTo() above.

MoveTo(float x, float y)/rMoveTo(float x, float y) moves to the target position

Both lines and Bezier curves take the current position as the starting point, rather than specifying the starting point. But you can indirectly set the starting point of these methods by changing the current position by moveTo(x, y) or rMoveTo().

paint.setStyle(Style.STROKE);
path.lineTo(100.100); / / draw diagonal lines
path.moveTo(200.100); / / I ~ ~
path.lineTo(200.0); / / draw a vertical barCopy the code

MoveTo (x, y) does not add graphics, but it sets the starting point of the graphics, so it is a very important helper method.

In addition, the second group has two special methods: arcTo() and addArc(). They are also used to draw lines, but do not use the current position as the starting point of the arc.

arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo) / arcTo(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean forceMoveTo) / arcTo(RectF oval, float startAngle, Float sweepAngle) draw arcs

This method has one less useCenter and one more forceMoveTo than canvas.drawarc ().

The useCenter is missing because arcTo() is only used to draw arcs, not scallops, so the useCenter argument is no longer needed; The extra forceMoveTo parameter means that a drawing should “move with a brush” or “drag the pen”, depending on whether it leaves traces of movement.

paint.setStyle(Style.STROKE);
path.lineTo(100.100);
path.arcTo(100.100.300.300, -90.90.true); // Forcibly move to the beginning of the arc (no trace)Copy the code

paint.setStyle(Style.STROKE);
path.lineTo(100.100);
path.arcTo(100.100.300.300, -90.90.false); // Connect to the beginning of the arc (with traces)Copy the code

addArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle) / addArc(RectF oval, float startAngle, float sweepAngle)

Again, an arc approach. One is called arcTo, one is called addArc(), they’re arcs, what’s the difference? It’s pretty simple: addArc() is just a simplified version of arcTo() that uses forceMoveTo = true directly.

paint.setStyle(Style.STROKE);
path.lineTo(100.100);
path.addArc(100.100.300.300, -90.90);Copy the code

Close () closes the current subgraph

Its function is to close the current subgraph, that is, draw a straight line from the current position to the starting point of the current subgraph.

paint.setStyle(Style.STROKE);
path.moveTo(100.100);
path.lineTo(200.100);
path.lineTo(150.150);
// The subgraph is not closedCopy the code

paint.setStyle(Style.STROKE);
path.moveTo(100.100);
path.lineTo(200.100);
path.lineTo(150.150);
path.close(); // Close the subgraph with close(). Equivalent to path.lineTo(100, 100)Copy the code

Close () and lineTo(starting point coordinates) are exactly equivalent.

“Child Shape” : Called contour in the official documentation. But since I couldn’t find a proper Chinese translation for the word in this scene (the literal translation would be “outline”), I switched to a word that Chinese people could understand: “sub-figure.” As mentioned earlier, the first group of methods is “add child graph”, by “child graph”, refers to a continuous line. A Path can contain more than one subgraph. When using the first set of methods, such as addCircle() and addRect(), each method call adds a separate child figure; However, when using the second group of methods, such as lineTo() arcTo() and so on, each line break (i.e., each “pen lift”) marks the end of a subgraph and the beginning of a new one.

Also, not all subgraphs need to be closed using close(). When a shape needs to be filled (Paint.Style is FILL or FILL_AND_STROKE), Path automatically closes the child shape.

paint.setStyle(Style.FILL);
path.moveTo(100.100);
path.lineTo(200.100);
path.lineTo(150.150);
// Only two edges are drawn here, but since the Style is FILL, it is automatically sealedCopy the code

So that’s the first class of Path methods: those that describe a Path directly.

The second type of Path method: auxiliary setup or calculation

There are fewer scenarios for using this method, and I won’t go through them here, except for one: setFillType(FillType FillType).

Path.setFillType(path. FillType ft) Sets the filling mode

Path.setFillType(fillType) is used to set the filling algorithm for self-intersecting graphs:

The method fills with different FillType values, resulting in different filling effects. The value of FillType can be:

  • EVEN_ODD
  • WINDING(Default value)
  • INVERSE_EVEN_ODD
  • INVERSE_WINDING

The last two, with the INVERSE_ prefix, are just inverse-colored versions of the first two, so it’s just a matter of figuring out the first two, EVEN_ODD and WINDING.

The principle of EVEN_ODD and WINDING is a bit complicated and too informative to say straight out, so I’ll give you a rough summary and give you a feel for it: WINDING is “full filling” and EVEN_ODD is “cross filling” :

It’s called “rough and Easy” because these are just general effects; And to know exactly how they work in all cases, you need to know how they work, that is, how they work.

EVEN_ODD and WINDING

EVEN_ODD

Even odd rule: For any point on the plane, if you shoot a ray in any direction, the number of times that ray intersects the graph. If it’s odd, then that point is considered to be inside the graph, the region to be colored. If it is an even number, the point is considered to be outside the graph, the area not to be colored in. Also take the double circle intersecting left and right as an example:

The direction of the ray does not matter, the ray from the same point in any direction, the result is the same, do not believe you can try.

As you can see from the figure above, each time a ray passes through a line in the graph, the internal and external states switch, which is why EVEN_ODD is a “cross-fill” mode.

WINDING

The non-zero winding rule: First of all, it requires that all the lines in your graph have a drawing direction:

Then, again, a ray is shot in any direction from a point in the plane, but the calculation is different: With 0 as the initial value, all the intersection for ray and graphics, meet every clockwise intersection (graphics through the rays on the left to the right) plus 1, the results met each intersection counterclockwise (graphics through the left from the right side of the ray) the results minus 1, in the end, all the intersection of the result if it is not 0, argues that the point within the graphics, Is the area to be colored; If it’s 0, then this point is considered to be outside the graph, the area that is not being colored.

As with EVEN_ODD, the direction of the ray does not affect the result.

So my previous “rough and easy” summary is not quite right about WINDING: if all your graphs are drawn in the same direction, then WINDING really is a “full fill” rule; But if the graph is drawn in a different direction, the result is different.

The direction of a graph: The direction of a method that adds a child graph class (such as path.addCircle () path.addRect ()) is controlled by the method’s dir argument, as discussed earlier; For line drawing methods (such as path.lineto () path.arcto ())), it is even simpler, and the direction of the line is the direction of the graph.

So the full version of EVEN_ODD and WINDING should look something like this:

INVERSE_EVEN_ODD and INVERSE_WINDING, it’s just the reverse of the two effects, you know EVEN_ODD and WINDING, so INVERSE_EVEN_ODD and INVERSE_WINDING, I won’t go into it.

Well, it took a long time to talk about drawPath(Path) and path, and we’re done. At the same time, Canvas’s drawing of graphics is also finished. If the graph is simple, use drawCircle() drawRect() and other methods to draw directly; For complex graphics, use drawPath() to draw custom graphics.

In addition, Canvas can draw bitmaps and text.

DrawBitmap (Bitmap Bitmap, float left, float top, Paint Paint) Draw a Bitmap

Draw a Bitmap, that is, paste over the contents of the pixels in the Bitmap. Where left and top are the position coordinates to draw the bitmap to. It’s very simple to use.

drawBitmap(bitmap, 200.100, paint);Copy the code

Its overloaded methods:

drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) /

drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) /

drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint)

DrawBitmap has a sibling method called drawBitmapMesh(), which draws a Bitmap with mesh stretching. DrawBitmapMesh () is used in a few scenarios, so I won’t go into that, but you can explore it yourself if you’re interested.

DrawText (String text, float x, float y, Paint Paint) Draws text

All display content in the interface is drawn out, including text. The drawText() method is used to drawText. The argument text is the string to draw, and x and y are the starting coordinates to draw.

canvas.drawText(text, 200.100, paint);Copy the code

Paint. SetTextSize (float textSize)

Using paint.settextSize (textSize), you can set the size of text.

paint.setTextSize(18);
canvas.drawText(text, 100.25, paint);
paint.setTextSize(36);
canvas.drawText(text, 100.70, paint);
paint.setTextSize(60);
canvas.drawText(text, 100.145, paint);
paint.setTextSize(84);
canvas.drawText(text, 100.240, paint);Copy the code

Setting the position and size of the text is just the most basic operation for drawing text. Text drawing is extremely customizable, but because it is so customizable, I will devote a whole installment to text drawing. I won’t talk about it in this issue.

HMM… That’s it. That’s the end of the first part of the Drawing section, the Canvas drawXXX() series of methods and the basic use of Paint.

Practice project

To avoid forgetting, it’s highly recommended that you strike while the iron is hot: HenCoderPracticeDraw1

Next up

Get ready for Paint, which is going to be a lot harder and a lot more fun. Finally, post some pictures of the next section as a preview:

Thank you

Thanks to readers who participated in this pre-release beta:

JiahuaAndroid, Huajinyuan, Quhuainan, Van Gogh, Stop and go, JK Sen, Street View, Tiger, Yiqi Line _, MadisonRong, AaronYi, Czwathou, Don’t say sorry to life, HML, Four leaves flower

appreciates

You give me money or not, I will do it seriously, with all my heart. So think carefully before you give money and make sure you want to appreciate it, not buy it.