preface

The purpose of this article is to give the reader a sense of the entire drawing process – the process through which an image is presented to the user.

Before we go through the process, we need to have a model

Explanation: When we draw a picture, we apply Paint to the Canvas, and then apply the Canvas to the phone screen. Therefore, if you want to enlarge or shrink the image, you should enlarge or shrink the image first and then draw it. This will come back to later). [there will be some articles that say – when onDraw(), ‘think logically and write logically backwards’]


Drawing process

With the basic model in place, let’s move on to the details of the drawing process.

There are three processes: Measure, Layout and Draw.

We don’t need to memorize, we can understand with logic. We start with the result, we need to draw a graph, and we always know where to draw it, so we need a layout. Layout is basically finding the four points (left,top,right,bottom) of the drawing, so that we know exactly where to put the drawing on the drawing board. Because the layout process needs to know the size of the graph, it needs to be measured before the layout. That way, we know that the measurement process is really just to get the size of the graph, but to get the result according to some rules (the constraints of the parent View and its own recommendations). So this whole process just comes out naturally.


Next, we’ll look at the three processes in terms of individual views and viewgroups.

Measurement process

A single View, usually the parent View triggers the onMeasure() of the child View via child.measure().

//ViewGroup source protected void measureChild(View Child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) { final LayoutParams lp = child.getLayoutParams(); final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight, lp.width); final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop + mPaddingBottom, lp.height); Measure (childWidthMeasureSpec, childHeightMeasureSpec); }Copy the code

And then the measure() method in the View

Public final void measure(int widthMeasureSpec, int heightMeasureSpec) { boolean optical = isLayoutModeOptical(this); if (optical ! = isLayoutModeOptical(mParent)) { //.... Omit unrelated to code the if (cacheIndex < 0 | | sIgnoreMeasureCache) {/ / measure ourselves, OnMeasure (widthMeasureSpec, heightMeasureSpec) this should set the measured dimension flag back; mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; } else { long value = mMeasureCache.valueAt(cacheIndex); // Casting a long to int drops the high 32 bits, no mask needed setMeasuredDimensionRaw((int) (value >> 32), (int) value); mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; }} // mark 1, Protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); }Copy the code

The onMeasure() method is the one we rewrote to get the size of the View according to the rules. MeasureSpec is a simple rule that is designed to understand the process and is not included in this article. How to use onLayout data obtained in onMeasure? We could of course store it as a variable, but in fact, we can retrieve width and height in onLayout by simply using setMeasuredDimension(Width,height).

Then, the whole process is as follows:

ViewGroup measurement process, the idea is to get their own width and height, that is mainly how to determine the width and height of the ViewGroup? That is, the width and height of the ViewGroup can be determined only after the width and height of all the children of the ViewGroup are determined. so


The layout process

A single view-layout process

Layout () is the layout entry, and setFrame() determines the View’s four points.

OnLayout () has an empty implementation because a single View is already positioned in layout()

ViewGroup – Layout process

Once you know how the individual views are laid out, then the ViewGroup itself is positioned, and then the sub-views are laid out.


Drawing process

From the source, can be divided into 7 steps

The main steps are: Draw the background – draw the content itself – draw the child View- draw the decorations (foreground, scrollbar, etc.), where dispatchDraw(Canvas) is an empty implementation for a single View

// Step 1, draw the background, if needed
drawBackground(canvas);

// Step 2, save the canvas' layers
int paddingLeft = mPaddingLeft;

// Step 3, draw the content
onDraw(canvas);

// Step 4, draw the children
dispatchDraw(canvas);

// Step 5, draw the fade effect and restore layers
final Paint p = scrollabilityCache.paint;
final Matrix matrix = scrollabilityCache.matrix;
final Shader fade = scrollabilityCache.shader;

// Step 6, draw decorations (foreground, scrollbars)
onDrawForeground(canvas);

// Step 7, draw the default focus highlight
drawDefaultFocusHighlight(canvas);
Copy the code


And finally, a complete mind map

If there is any doubt or doubt about the content. Welcome to comment section exchange, or private chat advice. Thank you very much.