Android 自定义viewAndroid技术知识Android知识

Android MeasureSpec

2017-06-10  本文已影响42人  reezy

MeasureSpec 封装了父元素对子元素宽(width)高(height)的布局需求。
MeasureSpec 由尺寸(size)与模式(mode)组成。

有以下三种测量模式:

子view的尺寸由 父view的MeasureSpec子view的LayoutParams 共同决定。

下表由 ViewGroup#getChildMeasureSpec 方法总结得来:

EXACTLY AT_MOST UNSPECIFIED
childSize childSize+EXACTLY childSize+EXACTLY childSize+EXACTLY
MATCH_PARENT size+EXACTLY size+AT_MOST (0或size)+UNSPECIFIED
WRAP_CONTENT size+AT_MOST size+AT_MOST (0或size)+UNSPECIFIED

附:ViewGroup#getChildMeasureSpec源码

/**   
 * @param spec 父view的测量值(MeasureSpec)
 * @param padding 父view的边距(padding,margin) 
 * @param childDimension 子view在布局参数尺寸(LayoutParam.width/LayoutParam.height) 
 */  
public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
    int specMode = MeasureSpec.getMode(spec);
    int specSize = MeasureSpec.getSize(spec);

    int size = Math.max(0, specSize - padding);

    int resultSize = 0;
    int resultMode = 0;

    switch (specMode) {
    // Parent has imposed an exact size on us
    case MeasureSpec.EXACTLY:
        if (childDimension >= 0) {
            resultSize = childDimension;
            resultMode = MeasureSpec.EXACTLY;
        } else if (childDimension == LayoutParams.MATCH_PARENT) {
            // Child wants to be our size. So be it.
            resultSize = size;
            resultMode = MeasureSpec.EXACTLY;
        } else if (childDimension == LayoutParams.WRAP_CONTENT) {
            // Child wants to determine its own size. It can't be
            // bigger than us.
            resultSize = size;
            resultMode = MeasureSpec.AT_MOST;
        }
        break;

    // Parent has imposed a maximum size on us
    case MeasureSpec.AT_MOST:
        if (childDimension >= 0) {
            // Child wants a specific size... so be it
            resultSize = childDimension;
            resultMode = MeasureSpec.EXACTLY;
        } else if (childDimension == LayoutParams.MATCH_PARENT) {
            // Child wants to be our size, but our size is not fixed.
            // Constrain child to not be bigger than us.
            resultSize = size;
            resultMode = MeasureSpec.AT_MOST;
        } else if (childDimension == LayoutParams.WRAP_CONTENT) {
            // Child wants to determine its own size. It can't be
            // bigger than us.
            resultSize = size;
            resultMode = MeasureSpec.AT_MOST;
        }
        break;

    // Parent asked to see how big we want to be
    case MeasureSpec.UNSPECIFIED:
        if (childDimension >= 0) {
            // Child wants a specific size... let him have it
            resultSize = childDimension;
            resultMode = MeasureSpec.EXACTLY;
        } else if (childDimension == LayoutParams.MATCH_PARENT) {
            // Child wants to be our size... find out how big it should
            // be
            
            // View.sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < M
            resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
            resultMode = MeasureSpec.UNSPECIFIED;
        } else if (childDimension == LayoutParams.WRAP_CONTENT) {
            // Child wants to determine its own size.... find out how
            // big it should be
            
            // View.sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < M
            resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
            resultMode = MeasureSpec.UNSPECIFIED;
        }
        break;
    }
    //noinspection ResourceType
    return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
}

附:View#getDefaultSize 源码

// 如果测量模式为UNSPECIFIED就返回指定的尺寸(size),否则从measureSpec中获取尺寸(specSize)
public static int getDefaultSize(int size, int 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;
}
上一篇 下一篇

猜你喜欢

热点阅读