View

Measure的具体流程:确定View的测量宽/高

1、 单个view的绘制流程

View_第1张图片
单一View的measure过程.png
  • measure()
/**
 * a. 绘制的入口
 * b. measure() 是final方法,即子类不能复写
 * @param widthMeasureSpec Horizontal space requirements as imposed by the
 *        parent
 * @param heightMeasureSpec Vertical space requirements as imposed by the
 *        parent
**/ 
public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
    // width/heightMeasureSpec:View的宽 / 高测量规格
        ...
    if (forceLayout || needsLayout) {
        ...
        if (cacheIndex < 0 || sIgnoreMeasureCache) {
            // measure ourselves, this should set the measured dimension flag back
            onMeasure(widthMeasureSpec, heightMeasureSpec);
        } else { ... }
    }
}
  • onMeasure()
/**
 * a. 计算视图大小:根据View宽 / 高的测量规格计算View的宽 / 高值:getDefaultSize()
 * b. 存储测量后的View宽 / 高:setMeasuredDimension()
**/ 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // width/heightMeasureSpec:View的宽 / 高测量规格

    // getDefaultSize(默认值,测量规格)
    setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
  • setMeasuredDimension()
// 存储测量后的View宽 / 高
protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
    boolean optical = isLayoutModeOptical(this);    
    if (optical != isLayoutModeOptical(mParent)) {
        Insets insets = getOpticalInsets();
        int opticalWidth  = insets.left + insets.right;
        int opticalHeight = insets.top  + insets.bottom;

        measuredWidth  += optical ? opticalWidth  : -opticalWidth;
        measuredHeight += optical ? opticalHeight : -opticalHeight;
    }
    setMeasuredDimensionRaw(measuredWidth, measuredHeight);
}

private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) {
    //传递测量后的子View的宽 / 高给环境变量mMeasuredWidth/Hegiht
    mMeasuredWidth = measuredWidth;
    mMeasuredHeight = measuredHeight;

    mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
    }
  • getDefaultSize()
/**
 *a. 测量模式为UNSPECIFIED,返回默认大小
 *b. 测量模式为AT_MOST,EXACTLY时,返回view测量后的宽 / 高值
**/ 
public static int getDefaultSize(int size, int measureSpec) {
    // size:默认大小
    // measureSpec:宽/高的测量规格(模式&测量大小) 

    int result = size;
    int specMode = MeasureSpec.getMode(measureSpec);
    int specSize = MeasureSpec.getSize(measureSpec);
    
    switch (specMode) {
        case MeasureSpec.UNSPECIFIED:
            result = size;
            break;
        case MeasureSpec.AT_MOST:
        case MeasureSpec.EXACTLY:
            result = specSize;
            break;
        }
        return result;
    }

A. specSizeView测量后的大小,非最终大小。最终大小是在layout阶段确定,但几乎所有情况下View的测量大小和最终大小相等。
B. 对于UNSPECIFIED这种情况,一般用于系统内部的测量过程,宽 / 高为getSuggestedMinimumWidth()/Height()的返回值。

  • getSuggestedMinimumWidth()
protected int getSuggestedMinimumWidth() {
    return (mBackground == null) ? 
        mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
}
//getSuggestedMinimumHeight()同理

A. 若View没有设置背景,View的宽度为mMinWidh
a. 其中mMinWidthandroid:minWidth属性所指定的值。
b. 若android:minWidth不指定,默认为0.
B. 若View设置了背景,View的宽度为max(mMinWidth, mBackground.getMinimumWidth())

  • DrawblegetMinimumWidth()
public int getMinimumWidth() {
    final int intrinsicWidth = getIntrinsicWidth();
    return intrinsicWidth > 0 ? intrinsicWidth : 0;
}
//getSuggestedMinimumHeight()同理

A. mBackground.getMinimumWidth()的大小 = 背景图Drawable的原始宽度
B. 若无原始宽度,则为0;
注:BitmapDrawable有原始宽度,而ShapeDrawable没有

你可能感兴趣的:(View)