• ViewRoot
    ViewRoot对应的实现类是ViewRootImpl类,他是连接WindowManager和DecorView的纽带,view的三大 流程均是通过ViewRoot来完成的。在ActivityThread中,当activity对象被创建完毕后,会将DecorView添加到Window中,同时会创建ViewRootImpl对象,并将ViewRootImpl对象和DecorView建立关联。
  • 三大流程
    measure performMeasure()->measure()->onMeasure()
    layout performLayout()->layout()->onLayout()
    draw performDraw()->draw()->onDraw()
  • MeasureSpec
    MeasureSpec代表一个32为int值,高2位代表SpecMode,低30位表示SpecSize。
    SpecMode有3类:
    1.UNSPENCIFIFD——父容器buduiview有限制,想要多大就多大,一般用于系统内部。
    2.EXACTLY——父容器已经检测出view所需要的精确大小,这个时候view的最终大小就是SpecSize指定的值。他对应于match_parent。
    3.AT_MOST——父容器指定一个大小,view大小不超过这个值。对应warp_content。

  • MeasureSpec和LayoutParams的对应关系
    对于普通的View,其measurespec由父容器的measurespec和自身的LayoutParams共同决定。
  • view采用固定宽高的时候,view的measurespec都是景区人模式并且大小遵循LayoutParams中的大小
  • 当view的宽高是match_parent的时候,如果父容器是精准模式,那么view也是精准模式并且大小是父容器的剩余空间。如果父容器是最大模式,view也是最大模式并且大小不会超过父容器剩余空间。
  • view是warp_content的时候, view的模式总是最大化并且不能超过父容器剩余空间。

measure过程

view的measure过程

view的measure有measure方法来完成。measure()方法中会调用onMeasure方法。代码如下

if (cacheIndex < 0 || sIgnoreMeasureCache) {
                // measure ourselves, this should set the measured dimension flag back
                onMeasure(widthMeasureSpec, heightMeasureSpec);
                mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
            }

onMeasure()方法代码如下,会调用getDefaultSize,返回的specSize就是测量后的大小

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
    }
protected int getSuggestedMinimumHeight() {
        return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight());

    }

如果view没有背景,view的高度就是mMinHeight,这个有android:minHeight控制。如果有背景,就是背景的最小高度。

ViewGroup的measure过程

viewgroup会测量子元素。

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);
            }
        }
    }
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);
    }

看到了layoutparams的身影。viewgroup是一个抽象类,跟着任教主,看看LinearLayout。

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mOrientation == VERTICAL) {
            measureVertical(widthMeasureSpec, heightMeasureSpec);
        } else {
            measureHorizontal(widthMeasureSpec, heightMeasureSpec);
        }
    }

measureVertical方法过于长,这个方法会测量子元素并记录目前的高度。


  • 在onCreate、onResume、onStart中去获取view的高度
  • onWindowFoucsChanged
  • view.post(Runnable)
  • ViewTreeObserver
  • view.measure() 这个比较复杂,具体的还的看书。

layout过程

确定4个顶点的位置,然后布局


draw过程

  • 绘制背景(background.draw)
  • 绘制自己(onDraw)
  • 绘制children(dispatchDraw)
  • 绘制装饰(onDrawScrollBars)

最后,关于自定义view,我觉得还是多去看看网上的一些大神给出的列子。这东西,看的多了,编的多了也就会了。