In a year of self-study on Android, Canvas has always been the class I can avoid, and I even do not hesitate to encapsulate my own drawing library to replace it.

Now looking back, the Canvas that abused me thousands of times is only so, calm down and have a look, in fact, it is not so bad as imagined. Just as it used to be hard for me at level 30 to hit a Level 40 Canvas, now I come back at level 50 to hit it. So friends, encounter can not bear the trouble, don’t be too depressed, go to other places to brush blame upgrade, once the level of improvement, sooner or later can “revenge” Android technology stack C, the first formal open:

If you take the analogy of View, Canvas, Paint, Coder(Coder) :

Then Canvas is a white paper in the black box. It can add layers and translate, rotate, scale, bevel, etc. The most important thing is that it has n drawXXX…

Paint is the brush used for drawing. Its feature is to provide drawing tools and special effects for drawing brushes (such as Cap, Join and six effects). View is the viewport that makes the black box transparent, which is also the most familiar to us. So the Coder is the person who’s manipulating the brush and drawing on the white paper, that’s the core


I. Preliminary preparation:

1. Customize canvas in View:

Speaking of Canvas objects, it seems that we seldom go to new them, and more often call back Canvas objects in the Ondraw method of custom controls

public class CanvasView extends View { public CanvasView(Context context) { this(context, null); } public CanvasView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } private void init() {@override protected void onDraw(Canvas) {super.ondraw (Canvas); // drawGrid drawGrid // drawGrid drawGrid}}Copy the code

It’s worth mentioning here: try not to create objects in onDarw, because view updates always go to onDarw() and open up space


2. Prepare grids and coordinates

Both are necessary to demonstrate drawing and are included in the Analyze package

Effect: given the origin of the coordinates will automatically draw the coordinate system and grid and numbers

1). Usage:
Private gridpaint; // Private gridpaint; // Private Point mWinSize; // Private Point mCoo; Release: // Prepare the screen size mWinSize = new Point(); mCoo = new Point(500, 500); Utils.loadWinSize(getContext(), mWinSize); mGridPaint = new Paint(Paint.ANTI_ALIAS_FLAG); //TODO drawGrid: release: HelpDraw. DrawGrid (Canvas, mWinSize, mGridPaint); //TODO drawCoo :release: helpdraw.drawCOO (Canvas, mCoo, mWinSize, mGridPaint);Copy the code
2). The grid – path auxiliary: com. Toly1994. C. iew. Analyze. HelpPath# gridPath
@param winSize @param winSize @param winSize */ public static path gridPath(int step, int step, int step, int step, int step) Point winSize) { Path path = new Path(); for (int i = 0; i < winSize.y / step + 1; i++) { path.moveTo(0, step * i); path.lineTo(winSize.x, step * i); } for (int i = 0; i < winSize.x / step + 1; i++) { path.moveTo(step * i, 0); path.lineTo(step * i, winSize.y); } return path; }Copy the code
2). The grid – drawing: com. Toly1994. C. iew. Analyze. HelpDraw# drawGrid
@param winSize * @param paint */ public static void drawGrid(canvas canvas, Point winSize, Paint Paint) {// Initialize the grid paintbrush paint.setStrokeWidth(2); paint.setColor(Color.GRAY); paint.setStyle(Paint.Style.STROKE); New float[]{visible, invisible}, offset paint. SetPathEffect (new DashPathEffect(new float[]{10, 5}, 0)); canvas.drawPath(HelpPath.gridPath(50, winSize), paint); }Copy the code
3). Assist – for the screen size: com. Toly1994. C. iew. Analyze the Utils# loadWinSize
/** * obtain screen height ** @param CTX Context * @param winSize screen size */ public static void loadWinSize(Context CTX, Point winSize) { WindowManager wm = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics outMetrics = new DisplayMetrics(); if (wm ! = null) { wm.getDefaultDisplay().getMetrics(outMetrics); } winSize.x = outMetrics.widthPixels; winSize.y = outMetrics.heightPixels; }Copy the code
4) coordinate system – path: com. Toly1994. C. iew. Analyze. HelpPath# cooPath
@param winSize @param winSize @return @param winSize @param winSize @return @param winSize */ public static Path cooPath(Point COO, Point winSize) { Path path = new Path(); Var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var path.lineTo(winSize.x, coo.y); Var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var path.lineTo(coo.x - winSize.x, coo.y); // veto (); // veto (); // Veto (); path.lineTo(coo.x, coo.y - winSize.y); // veto (); // veto (); // Veto (); path.lineTo(coo.x, winSize.y); return path; }Copy the code
5) coordinate system, drawing: com. Toly1994. C. iew. Analyze. HelpDraw# drawCoo
/** * @param Canvas * @param COO * @param winSize * @param paint */ public static void DrawCoo (Canvas Canvas, Point COO, Point winSize, Paint Paint) {// Initialize the grid paintbrush paint.setStrokeWidth(4); paint.setColor(Color.BLACK); paint.setStyle(Paint.Style.STROKE); New float[]{visible length, invisible length}, offset paint. SetPathEffect (null); DrawPath (helppath.coopath (COO, winSize), paint); // Canvas. DrawLine (winsize.x, coo. Y, winsize.x-40, COO.y-20, paint); canvas.drawLine(winSize.x, coo.y, winSize.x - 40, coo.y + 20, paint); X, winSize. Y, COO.x-20, winSize. Y-40, paint); canvas.drawLine(coo.x, winSize.y, coo.x + 20, winSize.y - 40, paint); DrawText4Coo (Canvas, COO, winSize, paint); } /** * Draw text for the frame ** @param canvas * @param COO * @param winSize * @param Paint */ Private static void DrawText4Coo (Canvas Canvas, Point COO, Point winSize, Paint Paint) {// Draw Paint. SetTextSize (50); canvas.drawText("x", winSize.x - 60, coo.y - 40, paint); canvas.drawText("y", coo.x - 40, winSize.y - 60, paint); paint.setTextSize(25); For (int I = 1; i < (winSize.x - coo.x) / 50; i++) { paint.setStrokeWidth(2); canvas.drawText(100 * i + "", coo.x - 20 + 100 * i, coo.y + 40, paint); paint.setStrokeWidth(5); canvas.drawLine(coo.x + 100 * i, coo.y, coo.x + 100 * i, coo.y - 10, paint); } for (int I = 1; i < coo.x / 50; i++) { paint.setStrokeWidth(2); canvas.drawText(-100 * i + "", coo.x - 20 - 100 * i, coo.y + 40, paint); paint.setStrokeWidth(5); canvas.drawLine(coo.x - 100 * i, coo.y, coo.x - 100 * i, coo.y - 10, paint); } for (int I = 1; i < (winSize.y - coo.y) / 50; i++) { paint.setStrokeWidth(2); canvas.drawText(100 * i + "", coo.x + 20, coo.y + 10 + 100 * i, paint); paint.setStrokeWidth(5); canvas.drawLine(coo.x, coo.y + 100 * i, coo.x + 10, coo.y + 100 * i, paint); } for (int I = 1; i < coo.y / 50; i++) { paint.setStrokeWidth(2); canvas.drawText(-100 * i + "", coo.x + 20, coo.y + 10 - 100 * i, paint); paint.setStrokeWidth(5); canvas.drawLine(coo.x, coo.y - 100 * i, coo.x + 10, coo.y - 100 * i, paint); }}Copy the code

2, Canvas drawing basic graphics (if you feel easy to skip)

I was a little impatient to see a class with a lot of methods, so many, how to remember.

Now I see a class with a lot of methods — wow, great, ha ha, even this method, the author really saved me to implement. I have divided the API of Canvas graphic drawing into the following categories: (color, dot, line, rectangle, circle, text, image, etc.)


1. Paint the color

/** * Draw the color. * @param canvas */ private void drawColor(canvas canvas) {// Canvas.drawcolor (color.parsecolor ("#E0F7F5")); // canvas.drawARGB(255, 224, 247, 245); // Canvas. DrawRGB (224, 247, 245); }Copy the code


2. Draw point

/** * drawPoint * @param canvas */ private void drawPoint(canvas canvas) {// drawPoint canvas.drawpoint (100, 100, mRedPaint); //// Draws a set of points, Canvas. DrawPoints (new float[]{400, 400, 500, 500, 600, 400, 700, 350, 800, 300, 900, 300}, mRedPaint); }Copy the code


3. Draw a line

/** * @param canvas */ private void drawLine(canvas canvas) {canvas. DrawLine (500, 200, 900, 400, mRedPaint); // Draw a set of points, Canvas. DrawLines (new float[]{200, 200, 400, 200, 400, 200, 200, 400, 200, 400, 200, 400, 400}, mRedPaint); }Copy the code


4. Draw a rectangle

/** * @param canvas */ private void drawRect(canvas canvas) {canvas.drawrect (100, 100, 500, 300, mRedPaint); Rect = new Rect(100, 100, 500, 300); // Rect = new Rect(100, 100, 500, 300); // canvas.drawRect(rect,mRedPaint); // canvas. DrawRoundRect (100 + 500, 100, 500 + 500, 300, 50, 50, mRedPaint); }Copy the code


5. Draw a circle

/** * draw a circle ** @param canvas */ private void drawLikeCircle(canvas canvas) {// Draw a circle (rectangle, brush) 100, mRedPaint); // canvas.drawOval(100, 100, 500, 300, mRedPaint); RectF rect = new RectF(100, 100, 500, 300); canvas.drawOval(rect, mRedPaint); RectF rectArc = new RectF(100 + 500, 100, 500 + 500, 300); // Draw the arc (rectangle boundary, start Angle, sweep Angle, use center? DrawArc (rectArc, 0, 90, true, mRedPaint); RectF rectArc2 = new RectF(100 + 500 + 300, 100, 500 + 500 + 300, 300); // Draw the arc (rectangle boundary, start Angle, sweep Angle, use center? Canvas. DrawArc (rectArc2, 0, 90, false, mRedPaint); }Copy the code


6. Draw pictures

@param canvas */ private void bitmap (canvas canvas) {//1. Fixed-point draw pictures Bitmap Bitmap = BitmapFactory. DecodeResource (getResources (), R.m ipmap. Menu_bg); canvas.drawBitmap(bitmap, 100, 100, mRedPaint); Matrix Matrix = new Matrix(); //2. SetValues (new float[]{1, 0.5f, 1500 * 3, 0, 1, 100 * 3, 0, 0, 3}); // setValues(new float[]{1, 0.5f, 1500 * 3, 0, 1, 100 * 3, 0, 0, 3}); canvas.drawBitmap(bitmap, matrix, mRedPaint); RectF rectf1 = new RectF(100 + 900, 100, 600 + 900, 400); canvas.drawBitmap(bitmap, null, rectf1, mRedPaint); Rect Rect = new Rect(300, 300, 400, 400); RectF rectf2 = new RectF(100 + 900, 100 + 400, 600 + 900, 400 + 400); canvas.drawBitmap(bitmap, rect, rectf2, mRedPaint); }Copy the code


7. Draw the Picture

1). At first, I was puzzled that “Picture” means “Picture”. Then I looked at the API:

/** * A Picture records drawing calls (via the canvas returned by beginRecording) * and can then play them back into Canvas (via {@link Picture#draw(Canvas)} or * {@link Canvas#drawPicture(Picture)}).For most content (e.g. text, lines, rectangles), * drawing a sequence from a picture can be faster than the equivalent API * calls, since the picture performs its playback without incurring any * method-call overhead. * * <p class="note"><strong>Note:</strong> Prior to API level 23 a picture cannot * be replayed on a hardware accelerated </p> < span style = "box-sizing: border-box; color: RGB (50, 50, 50); You can display this Canvas to another Canvas (either by Picture#draw(Canvas) or Canvas#drawPicture(Picture)). For most content, drawing from a Picture is faster than the corresponding API. You cannot display a picture on a hardware accelerated canvas before API level 23 because the presentation of a picture does not incur method call overhead.Copy the code

2). With a piece of code you can see exactly what it does

If you draw a character, you need this:

  private void drawPicture(Canvas canvas) {
        canvas.drawRect(100, 0, 200, 100, mRedPaint);
        canvas.drawRect(0, 100, 100, 200, mRedPaint);
        canvas.drawRect(200, 100, 300, 200, mRedPaint);
    }
Copy the code

If you want to reuse this font, most of you know, pan the canvas, copy and paste,

For small amounts of code, this is acceptable, but if it is a very complex graph, it wastes performance by drawing the same content each time

Private void drawPicture(Canvas Canvas) {// create Picture object Picture Picture = new Picture(); // Determine the size of the Canvas element generated by picture, Canvas recodingCanvas = picture.beginrecording (canvas.getwidth (), Canvas.getheight ()); // recodingCanvas. DrawRect (100, 0, 200, 100, mRedPaint); recodingCanvas.drawRect(0, 100, 100, 200, mRedPaint); recodingCanvas.drawRect(200, 100, 300, 200, mRedPaint); Picture.endrecording (); canvas.save(); canvas.drawPicture(picture); // Canvas. Translate (0, 300); picture.draw(canvas); // As above: Canvas. DrawPicture (picture); canvas.translate(350, 0); canvas.drawPicture(picture); canvas.restore();Copy the code

Picture is equivalent to taking a Picture first, and on another Canvas, on another Canvas, on another Canvas! It is important to say three times: when needed, paste it on the current canvas. The advantage of picture drawing is to save energy and reduce emissions. When there is a lot of complex content to reuse, the canvas component of picture is the best choice:


8. Draw text (the effect of the text is determined by Paint, details will be described in Paint)

/** * @param canvas */ private void drawText(canvas) {mredpaint.settextSize (100); Canvas. DrawText (" Toly", 200, 300, mRedPaint); }Copy the code

Finally, the boring code is finished.


Canvas transformation

Used to be tired of Canvas transformation, now see the key value is magic

As a generation of Photoshop master, I understand that saving and restoring the Canvas state should be as easy as a ball of hand, but why have I learned so recently

1. First look at the following figure: Set the origin of the coordinate system to (500,500)
    private void stateTest(Canvas canvas) {
        canvas.drawLine(mCoo.x + 500, mCoo.y + 200, mCoo.x + 900, mCoo.y + 400, mRedPaint);
//        canvas.rotate(45);
        canvas.drawRect(mCoo.x + 100, mCoo.x + 100, mCoo.y + 300, mCoo.y + 200, mRedPaint);
    }
Copy the code

So here’s the problem. What if I want to draw a rectangle that’s inclined by 45 degrees?

There seems to be no API for oblique rectangles. It seems to be too much trouble to find one point by one. I just turn the paper around. Rotate () is the rotate() method in the API.

    private void stateTest(Canvas canvas) {
        canvas.drawLine(mCoo.x + 500, mCoo.y + 200, mCoo.x + 900, mCoo.y + 400, mRedPaint);
        canvas.rotate(45);
        canvas.drawRect(mCoo.x + 100, mCoo.x + 100, mCoo.y + 300, mCoo.y + 200, mRedPaint);
    }
Copy the code

Sure enough, it turned upside down


2. Layer concept

Layers in Photoshop are the essence of Photoshop. It ensures that you can draw on one layer without affecting other layers

Each save() saves the previous state in the Canvas, creating a new drawing layer, we can draw as much as we want without affecting the other drawings already drawn, finally use restore() to merge this layer into the original layer. This is like the concept of stack. Every save(), New layer pushes (note that you can save multiple times), only the top layer can be operated, restore() pushes the stack


3. Rotate canvas :rotate()
private void stateTest(Canvas canvas) { canvas.drawLine(mCoo.x + 500, mCoo.y + 200, mCoo.x + 900, mCoo.y + 400, mRedPaint); canvas.drawRect(mCoo.x + 100, mCoo.x + 100, mCoo.y + 300, mCoo.y + 200, mRedPaint); canvas.save(); Rotate (45, McOo. x + 100, McOo. y + 100); rotate(45, McOo. x + 100, McOo. y + 100); mRedPaint.setColor(Color.parseColor("#880FB5FD")); canvas.drawRect(mCoo.x + 100, mCoo.x + 100, mCoo.y + 300, mCoo.y + 200, mRedPaint); canvas.restore(); // Merge layer down}Copy the code

4. Translate the canvas: Translate () : Write a bunch of McOos. Just move the canvas a little bit

The effect must change, is not a lot of refreshing

private void stateTest(Canvas canvas) { canvas.save(); canvas.translate(mCoo.x, mCoo.y); Canvas. DrawLine (500, 200, 900, 400, mRedPaint); canvas.drawRect(100, 100, 300, 200, mRedPaint); canvas.save(); //(Angle, center point x, center point y) Canvas. rotate(45, 100, 100); mRedPaint.setColor(Color.parseColor("#880FB5FD")); canvas.drawRect(100, 100, 300, 200, mRedPaint); canvas.restore(); // Merge the canvas. Restore () layer down; }Copy the code

5. Scale the canvas: Scale ()
private void stateTest(Canvas canvas) { canvas.save(); canvas.translate(mCoo.x, mCoo.y); Canvas. DrawLine (500, 200, 900, 400, mRedPaint); canvas.drawRect(100, 100, 300, 200, mRedPaint); canvas.save(); //(Angle, center point x, center point y) Canvas. Scale (2, 2, 100, 100); mRedPaint.setColor(Color.parseColor("#880FB5FD")); canvas.drawRect(100, 100, 300, 200, mRedPaint); canvas.restore(); // Merge the canvas. Restore () layer down; }Copy the code

6. Slash the canvas: Scale ()
private void stateTest(Canvas canvas) { canvas.save(); canvas.translate(mCoo.x, mCoo.y); Canvas. DrawLine (500, 200, 900, 400, mRedPaint); canvas.drawRect(100, 100, 300, 200, mRedPaint); canvas.save(); Canvas. Skew (1f,0f); mRedPaint.setColor(Color.parseColor("#880FB5FD")); canvas.drawRect(100, 100, 300, 200, mRedPaint); canvas.restore(); // Merge the canvas. Restore () layer down; }Copy the code

7. Select save state for canvas:

Public int save (int saveFlags) Store all state MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG ALL_SAVE_FLAG CLIP_SAVE_FLAG expired - saving only (not as layer) CLIP_TO_LAYER_SAVE_FLAG clip area Expired - Save FULL_COLOR_LAYER_SAVE_FLAG as layer only - save all color channels of the layer HAS_ALPHA_LAYER_SAVE_FLAG expired - Save alpha(opacity) channels of the layer only MATRIX_SAVE_FLAG expired -- Only saves Matrix information (Translate, Rotate, Scale, skew)Copy the code
int count = canvas.getSaveCount(); // Get the number of layers 3 Canvas.restoreToCount (1); // Restore directly to the layerCopy the code
4. Canvas clipping
1. It can be seen that there are mainly two types, inner cutting and outer cutting, and the Op operation is abandoned

2. Inner clipping :(save the contents drawn later in the region)
Private void clip(Canvas Canvas) {// Rect Rect = new Rect(20, 100, 250, 300); canvas.clipRect(rect); canvas.drawRect(0, 0, 200, 300, mRedPaint); }Copy the code

3. Outcropping :(save the content drawn outside the area)– note that API26 and above is available
Private void clip(Canvas Canvas) {// Rect Rect = new Rect(20, 100, 250, 300); canvas.clipOutRect(rect); canvas.drawRect(0, 0, 200, 300, mRedPaint); }Copy the code

So much for Canvas (note: Path drawing is covered in the Path section), the next section will cover Paint


Postscript: Jie wen standard

1. Growth record and Errata of this paper
Program source code The date of note
V0.1, The 2018-11-5 Android everything you know and don’t know about Canvas
V0.2, The 2018-11-6 Added “draw Picture” content
2. More about me
Pen name QQ WeChat hobby
Zhang Feng Jie te Li 1981462002 zdl1994328 language
My lot My Jane books My CSDN Personal website
3. The statement

1—- This article is originally written by Zhang Fengjie, please note if reproduced

2—- welcome the majority of programming enthusiasts to communicate with each other 3—- personal ability is limited, if there is something wrong welcome to criticize and testify, must be humble to correct 4—- see here, I thank you here for your love and support