View测量大小的影响因素汇总

之前面试的时候遇到一道问题,父View的属性(match_parent和wrap_content)对测量子view的影响,当时很蒙,没有回答上来,最近在看View源码的时候发现里面早已给出了标准答案,

先上源码

public static int getChildMeasureSpec(int spec, int padding, int childDimension) {

    //父View的宽/高测量模式
    int specMode = MeasureSpec.getMode(spec);
    //父View的宽/高大小
    int specSize = MeasureSpec.getSize(spec);

    //父View剩下的可用区域
    int size = Math.max(0, specSize - padding);

    int resultSize = 0;
    int resultMode = 0;

    switch (specMode) {
    //父View_EXACTLY
    case MeasureSpec.EXACTLY:
        //如果子View写si了宽/高
        if (childDimension >= 0) {
            //子View的MeasureSpec=EXACTLY+写si的宽/高(si说多了不吉利)
            resultSize = childDimension;
            resultMode = MeasureSpec.EXACTLY;
        } else if (childDimension == LayoutParams.MATCH_PARENT) {
            //子View的MeasureSpec=EXACTLY+父View剩下的区域
            resultSize = size;
            resultMode = MeasureSpec.EXACTLY;
        } else if (childDimension == LayoutParams.WRAP_CONTENT) {

            resultSize = size;
            resultMode = MeasureSpec.AT_MOST;
        }
        break;
    //父View_AT_MOST
    case MeasureSpec.AT_MOST:
        //如果子View写死了宽高
        if (childDimension >= 0) {
            //子View的MeasureSpec=EXACTLY+写si的宽/高
            resultSize = childDimension;
            resultMode = MeasureSpec.EXACTLY;
        } else if (childDimension == LayoutParams.MATCH_PARENT) {
            //子View的MeasureSpec=AT_MOST+父View剩下的区域
            resultSize = size;
            resultMode = MeasureSpec.AT_MOST;
        } else if (childDimension == LayoutParams.WRAP_CONTENT) {
            resultSize = size;
            resultMode = MeasureSpec.AT_MOST;
        }
        break;

    //父View_UNSPECIFIED从来没有用到,不做分析
    case MeasureSpec.UNSPECIFIED:
        if (childDimension >= 0) {

            resultSize = childDimension;
            resultMode = MeasureSpec.EXACTLY;
        } else if (childDimension == LayoutParams.MATCH_PARENT) {

            resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
            resultMode = MeasureSpec.UNSPECIFIED;
        } else if (childDimension == LayoutParams.WRAP_CONTENT) {

            resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
            resultMode = MeasureSpec.UNSPECIFIED;
        }
        break;
    }

    return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
}

从源码中不难看出,子View固定宽高:测量模式不受父View影响,全都为EXACTLY,宽高固定。 
当子View没有固定宽高:如果父View都为AT_MOST,子View想都别想还是为AT_MOST,如果父View为EXACTLY且子View的LayoutParams为match_parent,才为EXACTLY。宽高都为父View剩下的区域。这就很好的明白了为什么我们自定义View时,如果没对View的宽高进行处理,View即使是wrap_content也会撑满整个屏幕了。

综上可以得出结论:

父View在帮助计算子View的MeasureSpec时有着固定的套路: 
1.受父View的MeasureSpec影响 
2.受子View自身的LayoutParams影响 
3.计算父View剩下可用的区域,减去父View的padding和子View的margin距离和父View已经使用(预定)的区域大小。

参考文档:

https://blog.csdn.net/sinat_35938012/article/details/81055380

猜你喜欢

转载自blog.csdn.net/sinat_28496853/article/details/81349646