View drawing is basically completed by measure(), layout() and draw()

Number of letter As with Relevant methods
measure() Measure the width and height of View measure(),setMeasuredDimension(),onMeasure()
layout() Calculates the position of the current View and its children layout(),onLayout(),setFrame()
draw() View drawing draw(),onDraw()

A, the Measure

(1) MeasureSpec

MeasureSpec is the inner class of a View that encapsulates the dimensions and specifications of a View. A MeasureSpec encapsulates the layout requirements passed from parent to child, not from parent to child. A MeasureSpec encapsulates the layout requirements from parent to child. MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec

A MeasureSpec is a combination of size and mode. A MeasureSpec is an integer (32 bits) that encapsulates size and mode into an Int, where the first two bits are mode and the last 30 bits are size.

MeasureSpec has three modes:

model As with
EXACTLY The parent View has set the dimensions for the child View, and the child View should obey these boundaries, no matter how big the child container wants
AT_MOST Child containers can be any size within the declared size
UPSPECIFIED The parent container has no restrictions on the children, which can be as large as they want

A child’s MeasureSpec is determined by the parent’s MeasureSpec and the child’s LayoutParams. The child View’s LayoutParams are essentially converted from the layout_width and layout_height that we set when we wrote the XML. MeasureChildWithMargins is the one that measures the margins of the parent View, and then measures the margins of the parent View. MeasureChildWithMargins is the one that measures the margins of the parent View and then measures the margins of the parent View.

measureChildWithMargins

protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, Int parentHeightMeasureSpec, int heightUsed) {// LayoutParams, In XML layout_width and layout_height, the //layout_xxx value is finally encapsulated in this LayoutParams. final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); WidthUsed: widthUsed: widthUsed: widthUsed: widthUsed: widthUsed: widthUsed: widthUsed: widthUsed: widthUsed: widthUsed: widthUsed See the getChildMeasureSpec method for details. final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin + widthUsed, lp.width); final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin + heightUsed, lp.height); // A child View's MeasureSpec is a child View's MeasureSpec, and a child View's LayoutParams is a child View's measure. // If the subview is a ViewGroup, it will recursively measure down. child.measure(childWidthMeasureSpec, childHeightMeasureSpec); }Copy the code

getChildMeasureSpec

//spec: specifies the parent View's MeasureSpec; //padding: parent View padding + child View Margin //childDimension: the value of the child View's LayoutParams property (lp.width or lp.height), // can be match_parent, wrap_content, exact value; public static int getChildMeasureSpec(int spec, int padding, int childDimension) { int specMode = MeasureSpec.getMode(spec); SpecSize = MeasureSpec. GetSize (spec); // The size of the child View = the size of the parent View - own Padding int size = math.max (0, specsie-padding); int resultSize = 0; ResultMode = 0; // The child View's MeasureSpec int resultMode = 0; // The parent View is EXACTLY the same as the parent View. When the parent View asks for an exact value, the parent View is EXACTLY the same as the parent ViewcaseMeasureSpec.EXACTLY: // EXACTLY: width or height of a child View is an exact value, if the child View has its own size, use its own sizeif(childDimension >= 0) { resultSize = childDimension; ResultMode = MeasureSpec.EXACTLY; / / mode for EXACTLY. } // the width or height of the child View is MATCH_PARENT/FILL_PARENT, and the parent View size is assigned to the child Viewelse if(childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size. So be it. resultSize = size; ResultMode = MeasureSpec.EXACTLY; / / mode for EXACTLY. } // the width or height of the child View is WRAP_CONTENT, and the size of the parent View is the maximum size of the child Viewelse if(childDimension == LayoutParams.WRAP_CONTENT) { resultSize = size; ResultMode = MeasureSpec.AT_MOST; resultMode = MeasureSpec. / / mode for AT_MOST. }break; // The parent View is AT_MOST, that is, the parent View gives a maximum limit to the child ViewcaseMeasureSpec.AT_MOST: // the width or height of a child View is an exact value. If the child View has its own size, use its own sizeif(childDimension >= 0) { // Child wants a specific size... so be it resultSize = childDimension; ResultMode = MeasureSpec.EXACTLY; / / mode for EXACTLY. } // the width or height of the child View is MATCH_PARENT/FILL_PARENT, and the size of the parent View is the maximum size of the child Viewelse if(childDimension == LayoutParams.MATCH_PARENT) { resultSize = size; ResultMode = MeasureSpec.AT_MOST; resultMode = MeasureSpec. // The width or height of the child View is WRAP_CONTENT, and the size of the parent View is the maximum size of the child Viewelse if(childDimension == LayoutParams.WRAP_CONTENT) { resultSize = size; ResultMode = MeasureSpec.AT_MOST; resultMode = MeasureSpec. / / mode for AT_MOST}break; // The parent View is UNSPECIFIED, meaning that the parent View has no restrictions on its child viewscaseMeasureSpec.UNSPECIFIED: //3.1 The width or height of the child View is an exact value. If the child View has its own size, it uses its own sizeif(childDimension >= 0) { resultSize = childDimension; ResultMode = MeasureSpec.EXACTLY; //mode is EXACTLY} //3.2 Since the parent layout does not restrict the child View, when the child View is MATCH_PARENT the size is 0else if(childDimension == LayoutParams.MATCH_PARENT) { resultSize = 0; / / the size is zero! UNSPECIFIED resultMode = MeasureSpec.UNSPECIFIED; // Mode is UNSPECIFIED} //3.3 As the parent layout does not limit the child View, the size of the child View is set to 0 if the child View is WRAP_CONTENTelse if(childDimension == LayoutParams.WRAP_CONTENT) { resultSize = 0; / / the size is zero! UNSPECIFIED resultMode = MeasureSpec.UNSPECIFIED; / / mode for UNSPECIFIED}break; } // Build the MeasureSpec object based on the mode and size obtained by the above logical condition.return MeasureSpec.makeMeasureSpec(resultSize, resultMode);  
}    
Copy the code

It can be seen from the source code: If you write layout_width or layout_height to death in XML, you don’t need this measure at all, because match_parent fills the parent container, wrap_content ADAPTS to its size, When we’re writing code, it’s really cool to have Google calculate how big your match_parent is and how big your wrap_content is, and that’s how big your parent’s MeasureSpec is and how big your wrap_content is. Combined with child View’s LayoutParams and then calculate child View’s MeasureSpec, and then continue to pass to child View, constantly calculate each View’s MeasureSpec, child View has a MeasureSpec can more measure themselves and their child View.

1, If the parent View MeasureSpec is EXACTLY

A View’s MeasureSpec is EXACTLY the size of the parent View. If a View’s MeasureSpec is EXACTLY the size of the parent View, it is EXACTLY the size of the parent View.

(1) If the child View’s layout_xxxx is MATCH_PARENT, the parent View’s size is exact, and the child View’s size is MATCH_PARENT (which fills the entire parent View), then the child View’s size must be exact, and the size value is the parent View’s size. So child View size= parent View size, mode=EXACTLY.

(2) If the child View’s layout_xxxx is WRAP_CONTENT, that is, the size of the child View is determined by its content, but cannot exceed the size of the parent View. But the child View is WRAP_CONTENT, so we don’t know what the size of the child View is, To wait for the child. Measure (childWidthMeasureSpec childHeightMeasureSpec) calls to really only when measuring the size of the child View their content (such as TextView TextView wrap_content when measure the size of the content, which is the size of the character takes, this measure is in the child. The measure (childWidthMeasureSpec childHeightMeasureSpec), MeasureSpec = 100px; MeasureSpec = 50px; MeasureSpec = 50px; The parent View size is AT_MOST, and the parent View size is AT_MOST. The parent View size is AT_MOST and the parent View size is AT_MOST. MeasureSpec is a measure method parameter of a child View, a size constraint or requirement of a child View, and then a MeasureSpec child View implements its measurement.

(3) If the layout_xxxx of the child View is a certain value (200dp), then it is more simple, no matter what the mode and size of your parent View, I have written 200DP, then the control display is 200DP, no matter how big my parent View, I don’t care how big my content is, I’m just that big, so in this case my mode = EXACTLY, size=layout_xxxx.

Parent View MeasureSpec = AT_MOST

The size of the parent View is indeterminate. The maximum size of the parent View is MeasureSpec.

(1) If the child View’s layout_xxxx is MATCH_PARENT, the size of the parent View is uncertain, and the size of the child View is MATCH_PARENT, then the size of the child View is uncertain even if it is filled with the parent container. Mode =AT_MOST, size= parent View size, maximum is the parent View size.

(2) If the child View’s layout_xxxx is WRAP_CONTENT, the size of the parent View is uncertain, and the child View is WRAP_CONTENT, then the child View’s content is not calculated before the size. The maximum size of the child View is the size of the parent View, so the mode of the child View =AT_MOST, and size is temporarily set to the size of the parent View, maximum is the size of the parent View.

(3) If the subview layout_xxxx is a certain value (200dp), the same as above, write as much as possible, can not change.

The parent View’s MeasureSpec is UNSPECIFIED.

The child View can be as large as it wants without any constraints or constraints. Unlike AT_MOST, which indicates the maximum size, and EXACTLY, which indicates the exact size of the parent View.

As the parent View’s MeasureSpec is UNSPECIFIED, the parent View’s size is UNSPECIFIED, and the child View’s layout_xxxx is UNSPECIFIED. So for the child View, whether it is WRAP_CONTENT or MATCH_PARENT, there is no constraint on the child View. There is no requirement that the child View can be as big as it wants. Once there is no requirement or constraint, the value of size is meaningless, so it is generally set to 0.

As the parent View’s MeasureSpec is UNSPECIFIED, the parent View’s size is UNSPECIFIED, and the child View’s layout_XXXX is UNSPECIFIED. So for the child View, whether it is WRAP_CONTENT or MATCH_PARENT, there is no constraint on the child View. There is no requirement that the child View can be as big as it wants. Once there is no requirement or constraint, the value of size is meaningless, so it is generally set to 0.

(3) If the layout_xxxx of the subview is a certain value (200dp), you can write it as much as you want. (Remember, only the exact value is set, so no matter how you measure it, the size is the same.)

(2) onMeasure ()

The entrance of the whole measurement process is located in the measure method of View, which initializes some parameters and calls the onMeasure method. The measurement process is mainly in the onMeasure() method. The onMeasure method has the following source code:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                             getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
    }
Copy the code

Suggestedminimumwidth simple This is just one line of code that involves three methods: setMeasuredDimension, getDefaultSize, and getSuggestedMinimumWidth

GetSuggestedMinimumWidth () and getSuggestedMinimumHeight ()

// When the View has no background, the default size is mMinWidth, which corresponds to the Android:minWidth property and defaults to 0 if not set. // If background is set, the default size is mMinWidth and mBackground. GetMinimumWidth larger value of (). protected intgetSuggestedMinimumWidth() {
        return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
    }
Copy the code

getDefaultSize(int size, int measureSpec)

This method is used to obtain the default width and height of the View, combined with the source code.

Size = measureSpec = measureSpec = measureSpec = measureSpec = measureSpec = measureSpec Suggestedminimumwidth () is used to get the value. MeasureSpec is the measureSpec we analyzed earlier. Public static int getDefaultSize(int size, int measureSpec) {int result = size; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); // From this we can see that AT_MOST and EXACTLY are treated EXACTLY the same in View. So we have to deal with these two modes when we customize the View. switch (specMode) {case MeasureSpec.UNSPECIFIED:
            result = size;
            break;
        case MeasureSpec.AT_MOST:
        case MeasureSpec.EXACTLY:
            result = specSize;
            break;
        }
        return result;
    }
Copy the code

The first argument to getDefaultSize is size equal to the value returned by getSuggestedMinimumXXXX (the recommended minimum width and height), The recommended minimum width and height is determined by the Background size of the View and the minXXX property of the View. This size can be interpreted as the default size of the View, and the second parameter measureSpec is the parent View’s measureSpec. This measureSpec is calculated by measurement, As long as the mode of the test is not UNSPECIFIED, it is still UNSPECIFIED that the parent View’s MeasureSpec and the child View’s Own LayoutParams are mutually determined. The default is to use this measurement as the height of the View.

setMeasuredDimension(int measuredWidth, int measuredHeight)

This method is used to set the width and height of the View, and is often used when we customize the View. The default implementation of the View’s onMeasure method is simple: call setMeasuredDimension(). SetMeasuredDimension () can be understood as simply setting mMeasuredWidth and mMeasuredHeight. If these two values are set, it means that the measurement of the View is finished, and the width and height of the View have been measured. If we want to set the height and width of a View, we can use setMeasuredDimension (100,200) directly to set the height and width of the View (not recommended), but the setMeasuredDimension method must be called from the onMeasure method otherwise an exception will be thrown. Let’s look at what the default height and width is for a View.

After setMeasuredDimension(), you can call getMeasureWidth() and getMeasuredHeight() to get the measurewidth measured by the view, which yields 0 before calling both methods.

The measure process ends by calling the setMeasuredDimension() method in the onMeasure() method to set the measured size.

MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec As for other View derived classes, such as TextView, Button, ImageView, etc., their onMeasure methods have been rewritten. Instead of taking MeasureSpec size as the size, we can measure the height of characters or pictures first. And then get the View’s content height. If MeasureSpec is AT_MOST, and the size of the View’s content is within MeasureSpec’s size, then we can use the height of the View’s content. View size = MeasureSpec (MeasureSpec); View size = MeasureSpec;

(3) Measure process of ViewGroup

The measurement process of ViewGroup is a little different from View. It inherits from View and does not rewrite the measure method and onMeasure method of View.

Why not rewrite onMeasure? In addition to measuring the width and height of the ViewGroup, we also need to measure the size of each sub-view, and different layout measurement methods are different (see LinearLayout and FrameLayout), so there is no unified setting. So it provides measureChildren() and measureChild() methods to measure subviews. The general process is to iterate through all the child views and then call the View’s measure() method to make the child View measure itself.

A measureChildren() method is defined in the ViewGroup to measure the size of the subview, as shown below:

protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
    final int size = mChildrenCount;
    final View[] children = mChildren;
    for (int i = 0; i < size; ++i) {
        final View child = children[i];
        if((child.mViewFlags & VISIBILITY_MASK) ! = GONE) { measureChild(child, widthMeasureSpec, heightMeasureSpec); }}}Copy the code

The measureChild() method is called to measure the size of each subview of the current layout, as shown below:

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);
    child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
Copy the code

As you can see from the source code above, we call the getChildMeasureSpec() method to calculate the child’s MeasureSpec, and then call the child’s measure() method to pass in the calculated MeasureSpec.

Of course, the onMeasure() method can be overridden, meaning that if you don’t want to use the system’s default measurement, you can customize it as you wish. The measure process will take on different forms due to different layouts or requirements. It should be analyzed according to business scenarios. If you want to further study, you can take a look at the onMeasure method of LinearLayout.

Second, the Layout

The layout() process is used to calculate the position parameters of a View. For a ViewGroup, in addition to measuring its own position, it also needs to measure the position of its child views.

mView.measure(childWidthMeasureSpec, childHeightMeasureSpec); . mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());Copy the code

After the performTraversals method executes mView. Measure calculates mMeasuredXXX, the layout function is executed to determine the location of the View. The measured View only knows the size of the View matrix. That’s layout’s job. Layout puts a View tree in the right place according to the size of its subviews and layout parameters.

(a) layout (l, t, r, b)

Through the mView. Layout (0, 0, mView getMeasuredWidth (), mView. GetMeasuredHeight ()); Determine the position of the view. Since the Layout () method is the entry point to the layout process, take a look at the source code:

/** * The four parameters l, t, r, and b represent the distance between the left, top, right, and bottom boundaries of the View and its parent View. * */ public void layout(int l, int t, int r, int b) {if((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) ! = 0) { onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; } int oldL = mLeft; int oldT = mTop; int oldB = mBottom; int oldR = mRight; // Here passsetThe Frame orsetThe OpticalFrame method determines the position of the View in the parent container. Bool changed = isLayoutModeOptical(mParent);setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); // If the size and position of the View change, onLayout() is called to determine where all of the View's children are in the parent container. The onLayout method is an empty implementation, with different implementations for different layouts.if(changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { onLayout(changed, l, t, r, b); }}Copy the code

In the layout() method:

1. SetOpticalFrame (L,t,r,b) or setFrame(L,t,r,b) methods to determine whether the size of the view has changed to determine whether it is necessary to redraw the current view. SetFrame () is also called inside setOpticalFrame(). Look at the setFrame source code:

protected boolean setFrame(int left, int top, int right, int bottom) { ... MLeft = left; mLeft = left; mTop = top; mRight = right; mBottom = bottom; mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); }Copy the code

2, onLayout(changed, L, T, r, b) method is mainly ViewGroup to calculate the position of the child View. Once you know where you are, use onLayout() to determine the layout of the child View. OnLayout () is an inheritable empty method.

protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
}
Copy the code

If the current View is a single View, then there are no child views and you don’t need to implement this method.

If the current View is a ViewGroup, you need to implement the onLayout method, the method of the implementation of a custom ViewGroup of its characteristics, must be their own implementation.

After the onLayout() procedure is complete, we can call the getWidth() and getHeight() methods to get the width and height of the view.

Measurewidth () and getWidth() :

getMeasureWidth() getWidth()
It’s available after the measure() process It is available after the layout() procedure is complete
The value is set using the setMeasuredDimension() method The value is calculated by subtracting the left coordinate from the right coordinate of the view

(2) Summarize the layout process of View

Third, the Draw

Draw process is the process of View drawing to the screen, the entrance of the whole process in View draw() method, and the source notes are also written very clear, the whole process can be divided into 6 steps. In addition to 2 and 5 rarely used, through the various steps of the source analysis:

public void draw(Canvas canvas) {
    ...
        /*
         * Draw traversal performs several drawing steps which must be executed
         * inThe appropriate Order: * * 1. Draw the background if needed * 2. If necessary, save the current canvas * 3. Draw the View's contents * 4. Draw subview * 5. If necessary, draw edges, shadows, etc. * 6. */ // Step 1 If necessary, draw the background... background.draw(canvas); . // skip step 2 & 5if possible (common case)... // If necessary, save the current canvas...if (solidColor == 0) {
            final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;

            if(drawTop) { canvas.saveLayer(left, top, right, top + length, null, flags); }... // Step 3 Draw the contents of the Viewif(! dirtyOpaque) onDraw(canvas); // Step 4 draw sub-view dispatchDraw(canvas); If necessary, draw edges, shadows, etcif(drawTop) { matrix.setScale(1, fadeHeight * topFadeStrength); matrix.postTranslate(left, top); fade.setLocalMatrix(matrix); canvas.drawRect(left, top, right, top + length, p); }... OnDrawScrollBars (canvas); }Copy the code

Step1 background drawing

Just read the notes, not the point

private void drawBackground(Canvas canvas) { Drawable final Drawable background = mBackground; . // mright-mleft, mbottom-mtop Layout specifies four points to set the drawing area of the backgroundif (mBackgroundSizeChanged) { 
        background.setBounds(0, 0, mRight - mLeft, mBottom - mTop);   
        mBackgroundSizeChanged = false; rebuildOutline(); }... // Call Drawable draw() to draw the background image to the canvas background.draw(canvas); . }Copy the code

Step3 draw the content of View

/** * 3. Draw the contents of the View. This method is an empty implementation that handles itself in each business. */ protected void onDraw(Canvas canvas) { }Copy the code

OnDraw (canvas) method is the view used to draw their own, specific how to draw, color lines what style needs to be sub-view to achieve, view.java onDraw(canvas) is empty implementation.

Step4 draw all sub-views of the current View

/** * 4. Draw a subview. This method is an empty implementation in the View and is handled by the individual businesses. * dispatchDraw method is implemented in ViewGroup, mainly to traverse the subview, and call the subclass draw method, * generally we do not need to rewrite this method. */ protected void dispatchDraw(Canvas canvas) { }Copy the code

The dispatchDraw method is implemented in ViewGroup, mainly traversing the subview and calling the subclass draw method, generally we do not need to rewrite the method.

@Override
 protected void dispatchDraw(Canvas canvas) {
       ...
        if ((flags & FLAG_USE_CHILD_DRAWING_ORDER) == 0) {
            for (int i = 0; i < count; i++) {
                final View child = children[i];
                if((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() ! = null) { more |= drawChild(canvas, child, drawingTime); }}}else {
            for (int i = 0; i < count; i++) {
                final View child = children[getChildDrawingOrder(count, i)];
                if((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() ! = null) { more |= drawChild(canvas, child, drawingTime); }}}... }Copy the code

DrawChild () calls the view.draw () method. The ViewGroup class has already implemented the default process for drawing a child View. This implementation basically meets most of the requirements. So the subclasses of ViewGroup (LinearLayout,FrameLayout) basically don’t rewrite the dispatchDraw method.

DrawChild () allocates the appropriate Canvas clipping area for the child View. The size of the clipping area is determined by the Layout procedure. The location of the clipping area depends on the scroll value and the current animation of the child View. Once the clipping area is set, the subview’s draw() function is called to do the actual drawing.

Step6 draw the scroll bar of View

Not the point, onDrawScrollBars(canvas);

Summarize the drawing process of View

Four,

OnMeasure() — >OnLayout() — >OnDraw()

Main tasks of each step:

model As with
onMeasure() Measure view size. The measure method is recursively called from the top-level parent View to the child View, and the measure method calls back to the OnMeasure
onLayout() Locate the View and layout the page. The process of recursively calling the view.layout method from the top-level parent View to the child View, that is, the parent View puts the child View in the appropriate position according to the layout size and layout parameters obtained by measure child View in the previous step
onDraw() Draw the view, ViewRoot creates a Canvas object and calls OnDraw(). Six steps: (1) Draw the background; Save the canvas Layer. ③ Draw the content of the View; (4) Draw subview, if there is no use; ⑤, Draw edge, Shadow effect & Restore Layer; ⑥ draw the scroll bar

Five, thank you

Reference article:

Android View drawing process fully analyzed, take you step by step in-depth understanding of View(2)

Android View drawing process

Custom View Measure Process – the most understandable series of custom View principles

Custom View Layout process – the most easy-to-understand custom View principle series

Custom View Draw process – the most understandable custom View principle series