View測量大小的影響因素彙總
阿新 • • 發佈:2019-01-13
之前面試的時候遇到一道問題,父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