Detailed explanation of Canvas API (Part 1)


Introduction to this section:

We spent 13 sections explaining in detail most of the commonly used APIs of the Paint class in Android. Let’s start with this section. Some common APIs of Canvas (drawing board), we have listed them in

  • 8.3.1 Detailed explanation of three drawing tool classes
  • We can call them Some of the methods are divided into the following categories:
    • drawXxx method family: Draw a picture in the current drawing area with a certain coordinate value, and the layers will be superimposed. That is, the layer painted later will cover the layer painted previously.
    • clipXXX method family: Cut out (clip) a new drawing area in the current drawing area, this The drawing area is the current drawing area of ​​the canvas object. For example: clipRect(new Rect()), Then the rectangular area is the current drawing area of ​​canvas
    • getXxx method family: Get some values ​​related to Canvas, such as width, height, screen density, etc.
    • save(), restore(), saveLayer(), restoreToCount(), etc. save and restore layers The methods
    • translate(translation), scale(zoom), rotate(rotation), skew(tilt )

    Of course there are other scattered methods, well, starting from this section I will pick some interesting APIs to learn~

    And this section will give you What it brings is translate(translation), scale(zoom), rotate(rotation), skew(tilt) And detailed explanations of save(), restore()!

    Official API document: Canvas

    In addition, we must first clarify the direction of the X-axis and Y-axis in Canvas:

    1.png

1.translate(translation)

Method : translate(float dx, float dy)

Analysis: Translation, move the coordinate origin of the canvas x to the left and right, and y up and down. The default position of the canvas is (0,0)

Parameter : dx is the movement distance in the horizontal direction, dy is the movement distance in the vertical direction

Usage example:

for(int i=0; i < 5; i++) {
    canvas.drawCircle(50, 50, 50, mPaint);
    canvas.translate(100, 100);
}
Running effect

2.png


2.rotate(rotate)

Methodrotate(float degrees) / rotate(float degrees, float px, float py)

Analysis: Rotate degrees around the coordinate origin, the value is positive clockwise

Parameters: degrees is the rotation angle, px and py are the coordinates of the center point of the specified rotation (px, py)

Usage example:

Rect rect = new Rect(50,0,150,50);
canvas.translate(200, 200);
for(int i = 0; i < 36;i++){
    canvas.rotate(10);
    canvas.drawRect(rect, mPaint);
}

Running effect:

3.png

Code Analysis:

Here we first call translate(200,200) to move the coordinate origin of the canvas to (200,200), and then draw, so we The drawing result can be completely displayed on the canvas. If we set (10,200,200) for rotate, it will look like this Result:

4.png

Do you have any questions? This involves the concept of multiple layers of Canvas. I will talk about it later~


3.scale( Scale)

##Method: scale(float sx, float sy) / scale(float sx, float sy, float px , float py)

Analysis: Scale the canvas

Parameters: sx is the horizontal scaling ratio, sy is the vertical scaling I don’t know the ratio, px and py either. Decimal means to reduce , Integer means to enlarge

Usage example:

canvas.drawBitmap(bmp,0,0,mPaint);
canvas.scale(0.8f, 0.8f);
canvas.drawBitmap(bmp, 0, 0, mPaint);
canvas.scale(0.8f, 0.8f);
canvas.drawBitmap(bmp,0,0,mPaint);

Running effect:

5.png


4.skew(skew)

method skew(float sx, float sy)

Analysis: Slant, can also be translated as bevel, twist

Parameter : sx is the corresponding angle of tilt in the x-axis direction, sy is the corresponding angle of tilt in the y-axis direction, both values ​​are tan values! They are all tan values! They are all tan values! For example, if you want to tilt 60 degrees in the x-axis direction, then the decimal value corresponds to: tan 60 = square root 3 = 1.732!

Usage example:

canvas.drawBitmap(bmp,0,0,mPaint);
canvas.translate(200, 200);
canvas.skew(0.2f,-0.8f);
canvas.drawBitmap(bmp,0,0,mPaint);

Running effect:

6.png

##5. The concept of Canvas layer and detailed explanation of save() and restore()

We generally like to call Canvas canvas, and children always think that Canvas is A simple piece of drawing paper, then I think I would like to ask how multi-layer animation is completed using canvas? In the example of translate above, why? drawCircle(50, 50, 50, mPaint); The reference coordinate is always (50,50), so why does this effect occur? Children who have doubts may have been confusing the concept of screen with the concept of Canvas. Let’s restore it below. The crime scene where translate was called:

7.png

As shown in the figure, the origin of the canvas coordinates moves 100 on the x and y axes each time; then if we want to return to (0,0) What about drawing new graphics at different points? How to break, translate(-100,-100) slowly translates back? Not really Confused...8.jpg

Okay, let’s not get involved. We can save the current canvas state before doing translation transformation. In fact, Canvas is We provide support for layers, and these layers are managed according to the "stack structure"

9.png

When we call the save() method , will save the current Canvas state and add it to the Canvas stack as a Layer. In addition, this Layer is not a specific class, it is just a conceptual thing!

And when we call the restore() method, the previous Canvas state will be restored, and at this time the Canvas layer stack The Layer on the top of the stack will pop up, and the subsequent Layer will come to the top of the stack. At this time, the Canvas will return to the Canvas state saved at the top of the stack!

Simply put: save() pushes a Layer into the stack, and restore() pops up a Layer on the top of the stack. This Layer represents the Canvas. state! That is to say, you can save() multiple times or restore() multiple times, but the number of restore calls cannot be greater than save Otherwise an error will be thrown! This is what most people say on the Internet, but in actual testing no such problem occurred, even if I restored The number of times is more than save, and there are no errors~ Visual inspection is that the system has been changed. I will show it to everyone after the next test~Come on, write an example to verify the function of save and restore! 10.gif

Write an example:

Example code:

canvas.save();  //保存当前canvas的状态

canvas.translate(100, 100);
canvas.drawCircle(50, 50, 50, mPaint);

canvas.restore();  //恢复保存的Canvas的状态
canvas.drawCircle(50, 50, 50, mPaint);

Running result:

11.pngNeedless to say, the code and results have explained everything, let’s make it more complicated and let’s do it Multiple save() and restore()!

Example code:

canvas.save();

canvas.translate(300, 300);
canvas.drawBitmap(bmp, 0, 0, mPaint);
canvas.save();

canvas.rotate(45);
canvas.drawBitmap(bmp, 0, 0, mPaint);
canvas.save();

canvas.rotate(45);
canvas.drawBitmap(bmp, 0, 0, mPaint);
canvas.save();

canvas.translate(0, 200);
canvas.drawBitmap(bmp, 0, 0, mPaint);

Run result:

12.png

Result Analysis:

First translate (300,300) to draw, then rotate 45 degrees to draw, then rotate 45 degrees to draw, then translate (0,200), During this period, save() is performed every time before drawing. You may have a question when you see this. The last translation is not a y movement of 200. Well, why did it turn to the left? Hehe, I will tell you that rotate() rotates the entire coordinate axis? coordinate axis Variety:

13.png

Well, you understand rotate(), right? That’s ok, then let’s try restore~ We are in front of the final drawing Add two restore()!

canvas.restore();
canvas.restore();
canvas.translate(0, 200);
canvas.drawBitmap(bmp, 0, 0, mPaint);

Run result:

14.png

Don’t say anything, experience it yourself, and add morerestore()!

15.png

It’s interesting, let’s continue adding restore()

17.png

##Well, it seems that we can’t write

restore anymore, right? Because we only saved four times. According to the Internet, This will report an error, is that really the case? Here we call the one provided by Canvas to get the current stack How many Layer methods are there: getSaveCount(); and then before and after save() and restore() Add a Log to print out the number of Layers in the stack:

18.png

The result is really gratifying. After all, practice brings true knowledge. It may be that Canvas has been modified, or for other reasons. Here You have to look at the source code to find out. Due to time constraints, here we know that the number of restores can be more than the number of saves. However, it is still recommended to restore less often than save to avoid unnecessary problems~ As for the process of entering and exiting the stack, I won’t talk about it. I drew it myself and it is very easy to understand!


6. Explanation of saveLayer() and restoreToCount()

In fact, these two methods are similar to save and restore, but there are some more things based on the latter. Just the East, For example, saveLayer() has the following overloaded methods:

19.png

You can understand that the

save() method saves the entire Canvas , and saveLayer() can selectively save the state of a certain area. In addition, we see that there is: int saveFlags in the room and board, this is the setting to change the object to be saved! Optional values ​​are:

Save the entire stateSave the state of a cropped areaSave the status in the preset range##FULL_COLOR_LAYER_SAVE_FLAGHAS_ALPHA_LAYER_SAVE_FLAG##MATRIX_SAVE_FLAGPS: There is something wrong with the above description. The author’s English level is low, maybe Wrong, if you know anything, please be sure to correct me, thank you~
TagDescription
##ALL_SAVE_FLAG
CLIP_SAVE_FLAG
CLIP_TO_LAYER_SAVE_FLAG
Save Color coating
opaque layer save
Save the state of Matrix information (translate, rotate, scale, skew)
Here we write an example to verify: We choose the

CLIP_TO_LAYER_SAVE_FLAG

mode to write an example

Implementation code

:

RectF bounds = new RectF(0, 0, 400, 400);
canvas.saveLayer(bounds, mPaint, Canvas.CLIP_TO_LAYER_SAVE_FLAG);
canvas.drawColor(getResources().getColor(R.color.moss_tide));
canvas.drawBitmap(bmp, 200, 200, mPaint);
canvas.restoreToCount(1);
canvas.drawBitmap(bmp, 300, 200, mPaint);
Running result

:

Let’s study it in detail later on saveLayer() ~Here is a general idea~20.png

Then go to this

restoreToCount(int)

, this is simpler, directly pass in the number of Layers to be restored, Jump directly to the corresponding layer, and at the same time kick all the Layers above the layer out of the stack, so that the layer Become the top of the stack~! It’s much more convenient and faster than writing multiple restore()~

7. Download the code sample in this section:


Well, the code is written for testing, so there is no need to It doesn’t make sense, but maybe readers still want it, so just post the link!

Code download

:

CanvasDemo.zipMaybe this is the picture you want! Haha~

21.jpgSummary of this section:


This section was written after a few days of struggle, because the author was not sure about it at the beginning. The concept of this Canvas layer is not very clear either. I finished my work this afternoon and thought about my thoughts. I worked overtime in the evening and finally wrote this article. I believe it will be helpful. Everyone understands Canvas more clearly, and you won’t be confused when advanced custom controls~ Hehe, that’s it for this section. If there are any mistakes, please point them out, thank you very much~

21.gif