欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-05-27 11:51:40
...

之前面试的时候遇到一道问题,父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