Android_View的绘制过程

View可以看成一个树形结构,父控件是父节点,子控件是子节点。View的绘制过程就是遍历这棵树。

View的绘制有三步:

  1. measure:测量View的Width和Height,
  2. layout:布局View(left,right,top,bottom),指定View和手机屏幕的上下左右的距离。
  3. draw:绘图

以上的步骤必须按照顺序来。(顺便说一下,以上三个步骤发生在View的构造方法之后。)

measure是绘制视图的第一步,因为只有知道的View的大小(Width和Height)才能绘图。

我们在编写layout的xml文件的时候,会遇到layout_width和layout_height两个属性,对于这两个属性我们有三个选择:fill_parent、wrap_content和具体值,measure就是用来处理fill_parent、wrap_content两个属性的,在绘图的时候,要知道具体的值,所以要计算fill_parent、wrap_content的具体值。

下面是几个重要的函数和参数:

  1. public final void measure(int widthMeasureSpec, int heightMeasureSpec)
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
  3. protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec)
  4. protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec)
  5. protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed)

前两个方法是View类里面的方法,后三个方法是ViewGroup类里面的方法。

先来看看measure的源码:

/**
     * <p>
     * This is called to find out how big a view should be. The parent
     * supplies constraint information in the width and height parameters.
     * </p>
     *
     * <p>
     * The actual mesurement work of a view is performed in
     * {@link #onMeasure(int, int)}, called by this method. Therefore, only
     * {@link #onMeasure(int, int)} can and must be overriden by subclasses.
     * </p>
     *
     *
     * @param widthMeasureSpec Horizontal space requirements as imposed by the
     *        parent
     * @param heightMeasureSpec Vertical space requirements as imposed by the
     *        parent
     *
     * @see #onMeasure(int, int)
     */
    public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
        if ((mPrivateFlags & FORCE_LAYOUT) == FORCE_LAYOUT ||
                widthMeasureSpec != mOldWidthMeasureSpec ||
                heightMeasureSpec != mOldHeightMeasureSpec) {

            // first clears the measured dimension flag
            mPrivateFlags &= ~MEASURED_DIMENSION_SET;

            if (ViewDebug.TRACE_HIERARCHY) {
                ViewDebug.trace(this, ViewDebug.HierarchyTraceType.ON_MEASURE);
            }

            // measure ourselves, this should set the measured dimension flag back
            onMeasure(widthMeasureSpec, heightMeasureSpec);

            // flag not set, setMeasuredDimension() was not invoked, we raise
            // an exception to warn the developer
            if ((mPrivateFlags & MEASURED_DIMENSION_SET) != MEASURED_DIMENSION_SET) {
                throw new IllegalStateException("onMeasure() did not set the"
                        + " measured dimension by calling"
                        + " setMeasuredDimension()");
            }

            mPrivateFlags |= LAYOUT_REQUIRED;
        }

        mOldWidthMeasureSpec = widthMeasureSpec;
        mOldHeightMeasureSpec = heightMeasureSpec;
    }
measure方法是final类型的,所以不能被继承,不能被复写。而measure方法里面调用了onMeasure方法,onMeasure方法可以被继承,可以被复写。下面是onMeasure源码:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
    }
onMeasure默认的实现仅仅调用了setMeasuredDimension,setMeasuredDimension函数是一个很关键的函数,它对View的成员变量mMeasuredWidth和mMeasuredHeight变量赋值,而measure的主要目的就是对View树中的每个View的mMeasuredWidth和mMeasuredHeight进行赋值,一旦这两个变量被赋值,则意味着该View的测量工作结束。

setMeasuredDimension源码如下:

    protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
        mMeasuredWidth = measuredWidth;
        mMeasuredHeight = measuredHeight;

        mPrivateFlags |= MEASURED_DIMENSION_SET;
    }
再来看下MeasureSpec这个类,MeasureSpec参数的值为int型,分为高32位和低16为,高32位保存的是specMode,低16位表示specSize,specMode分三种:
  1. MeasureSpec.UNSPECIFIED:父视图不对子视图施加任何限制,子视图可以得到任意想要的大小
  2. MeasureSpec.EXACTLY:父视图希望子视图的大小是specSize中指定的大小
  3. MeasureSpec.AT_MOST:子视图的大小最多是specSize中的大小

以上施加的限制只是父视图“希望”子视图的大小按MeasureSpec中描述的那样,但是子视图的具体大小取决于多方面的

你可能感兴趣的:(Android_View的绘制过程)