view的視圖有兩種情況:
- 內容型視圖:由視圖的內容決定其大小。
- 圖形型視圖:父視圖為view動態調整大小。
### measure的本質
把視圖布局使用的“相對值”轉化成具體值的過程,即把WRAP_CONTENT,MATCH_PARENT轉化為具體的值。
measure內部的設計思路
再來看一下View中measure()函數原型:
public final void measure(int widthMeasureSpec, int heightMeasureSpec);
當父視圖對子視圖進行measure操作時,會調用子視圖的measure()方法。該函數的意思是父視圖為子視圖所提供的measure的”規格”,因為父視圖最終為子視圖提供的”窗口”大小是由父視圖和子視圖共同決定的。該值有32位組成,高16位保存的是specMode, 低16位保存spcMode。
spceMode有三種:
- MeasureSpec.EXACTLY: “確定的”, 父視圖希望子視圖的大小應該是spec中指定的。在一般情況下, View的設計者應該遵守指示,將View的measureHeight和measuredWidth設置成指定的值。
- MeasureSpec.AT_MOST:”最多”,子視圖最多是specSize中指定的值。
- MeasureSpec.UNSPECIFIED: “沒有限制”, 此時View的設計者可以根據自身的特性設置視圖的大小。
以上介紹measureSpec的語義,該參數是父視圖傳遞給子視圖的,看一下measureSpec是如何產生的:
ViewRoot中,調用host.measure()函數,參數分別是局部變量childWidthMeasureSpec和childHeightMeasureSpec,這兩個變量的賦值最初是通過調用getRootMeasureSpec()函數獲得的:
childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
childHeightMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.height);
ViewGroup中的measureChildWidthMargins()
- 調用child.getLayoutParams()獲得子視圖的LayoutParams屬性。
- 調用兩次getChildMeasureSpec()函數,分別計算出該子視圖的寬度和高度的spec。
- 調用child.measure()函數。子視圖可以重載onMeasure()函數,并調用setMeasureDimension()函數設置任意大小的布局,這將成為子視圖的最終布局大小。