一、启动:每个Activity 均会创建一个 PhoneWindow对象,是Activity和整个View系统交互的接口,每个Window都对应着一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立联系,对于Activity来说,ViewRootImpl是连接WindowManager和DecorView的纽带,绘制的入口是由ViewRootImpl的performTraversals方法来发起Measure,Layout,Draw等流程的。

二、Measure过程:

1、MeasureSpec 的理解

是view的一个大小和模式的组合,


  • MeasureSpec中的值是一个整型(32位)将size和mode打包成一个Int型,其中高两位是mode,后面30位存的是size,是为了减少对象的分配开支。MeasureSpec 类似于下图,只不过这边用的是十进制的数,而MeasureSpec 是二进制存储的。

  • MesureSpec三种模式

UPSPECIFIED : 父容器对于子容器没有任何限制,子容器想要多大就多大
EXACTLY: 父容器已经为子容器设置了尺寸,子容器应当服从这些边界,不论子容器想要多大的空间。
AT_MOST:子容器可以是声明大小内的任意大小

父View的measure的过程会先测量子View,等子View测量结果出来后,再来测量自己,上面的measureChildWithMargins就是用来测量某个子View的,通过父view的measurespec的model确定子view的resultmodel和resultsize;


  • 如果父View的MeasureSpec 是EXACTLY,说明父View的大小是确切的,(确切的意思很好理解,如果一个View的MeasureSpec 是EXACTLY,那么它的size 是多大,最后展示到屏幕就一定是那么大)。
  • 如果父View的MeasureSpec 是AT_MOST,说明父View的大小是不确定,最大的大小是MeasureSpec 的size值,不能超过这个值。
  • 如果父View的MeasureSpec 是UNSPECIFIED(未指定),表示没有任何束缚和约束,不像AT_MOST表示最大只能多大,不也像EXACTLY表示父View确定的大小,子View可以得到任意想要的大小,不受约束

ViewGroup的Measure过程

ViewGroup并没有实现onMeasure,他会根据具体实现的onMeasure来measure所有子view的宽高。

三、layout


1.performTraversals 方法执行完mView.measure 计算出mMeasuredXXX后就开始执行layout 函数来确定View具体放在哪个位置,我们计算出来的View目前只知道view矩阵的大小,具体这个矩阵放在哪里,这就是layout 的工作了。

2.如果当前ViewGroup未添加LayoutTransition动画,或者LayoutTransition动画此刻并未运行,那么调用super.layout(l, t, r, b),继而调用到ViewGroup中的onLayout,否则将mLayoutSuppressed设置为true,等待动画完成时再调用requestLayout()。


3.然后调用setFrame(l, t, r, b) 可以理解为给mLeft 、mTop、mRight、mBottom赋值


4.回调onLayout,对于View来说,onLayout只是一个空实现,对于viewgroup来说,onLayout是一个抽象方法,继承viewgroup需实现onLayout,一般是遍历子view然后调用子view的layout方法



四、draw


performTraversals 方法的下一步就是mView.draw(canvas); 因为View的draw 方法一般不去重写,官网文档也建议不要去重写draw 方法



public void draw(Canvas canvas) {
    ...
        /*
         * Draw traversal performs several drawing steps which must be executed
         * in the appropriate order:
         *
         *      1. Draw the background
         *      2. If necessary, save the canvas' layers to prepare for fading
         *      3. Draw view's content
         *      4. Draw children
         *      5. If necessary, draw the fading edges and restore layers
         *      6. Draw decorations (scrollbars for instance)
         */

        // Step 1, draw the background, if needed
    ...
        background.draw(canvas);
    ...
        // skip step 2 & 5 if possible (common case)
    ...
        // Step 2, save the canvas' layers
    ...
        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 content
        if (!dirtyOpaque) onDraw(canvas);

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

        // Step 5, draw the fade effect and restore layers

        if (drawTop) {
            matrix.setScale(1, fadeHeight * topFadeStrength);
            matrix.postTranslate(left, top);
            fade.setLocalMatrix(matrix);
            canvas.drawRect(left, top, right, top + length, p);
        }
    ...
        // Step 6, draw decorations (scrollbars)
        onDrawScrollBars(canvas);
    }

public void draw(Canvas canvas) {
    ...
        /*
         * Draw traversal performs several drawing steps which must be executed
         * in the appropriate order:
         *
         *      1. Draw the background
         *      2. If necessary, save the canvas' layers to prepare for fading
         *      3. Draw view's content
         *      4. Draw children
         *      5. If necessary, draw the fading edges and restore layers
         *      6. Draw decorations (scrollbars for instance)
         */

        // Step 1, draw the background, if needed
    ...
        background.draw(canvas);
    ...
        // skip step 2 & 5 if possible (common case)
    ...
        // Step 2, save the canvas' layers
    ...
        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 content
        if (!dirtyOpaque) onDraw(canvas);

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

        // Step 5, draw the fade effect and restore layers

        if (drawTop) {
            matrix.setScale(1, fadeHeight * topFadeStrength);
            matrix.postTranslate(left, top);
            fade.setLocalMatrix(matrix);
            canvas.drawRect(left, top, right, top + length, p);
        }
    ...
        // Step 6, draw decorations (scrollbars)
        onDrawScrollBars(canvas);
    }



1、第一步:背景绘制

2、第三步,对View的内容进行绘制。

3、第4步 对当前View的所有子View进行绘制(dispatchDraw)

4、第6步 对View的滚动条进行绘制

Android自定义view画一个曲线效果 android view的绘制流程_onDraw