最近一直想作一個本身定義組建可一直苦於OnMeasure()不知道怎麼用,剛纔終於有時間來整理下個人東西了。
咱們知道View在屏幕上顯示出來要先通過measure和layout. 在調用onMeasure(int widthSpec, int heightSpec)方法時,要涉及到MeasureSpec的使用,MeasureSpec有3種模式分別是
UNSPECIFIED, EXACTLY和AT_MOST
, 那麼這些模式和咱們平時設置的layout參數fill_parent, wrap_content有什麼關係呢。
通過代碼測試就知道,當咱們設置width或height爲fill_parent時,容器在佈局時調用子 view的measure方法傳入的模式是EXACTLY,由於子view會佔據剩餘容器的空間,因此它大小是肯定的。而當設置爲 wrap_content時,容器傳進去的是AT_MOST, 表示子view的大小最可能是多少,這樣子view會根據這個上限來設置本身的尺寸
。當子view的大小設置爲精確值時,容器傳入的是EXACTLY, 而MeasureSpec的UNSPECIFIED模式目前尚未發如今什麼狀況下使用。
View的onMeasure方法默認行爲是當模式爲UNSPECIFIED時,設置尺寸爲mMinWidth(一般爲0)或者背景drawable的最小尺寸,當模式爲EXACTLY或者AT_MOST時,尺寸設置爲傳入的MeasureSpec的大小。
有個觀念須要糾正的是,fill_parent應該是子view會佔據剩下容器的空間,而不會覆蓋前面已佈局好的其餘view空間,固然後面佈局子 view就沒有空間給分配了,因此fill_parent屬性對佈局順序很重要。之前所想的是把全部容器的空間都佔滿了,難怪google在2.2版本里 把fill_parent的名字改成match_parent. java
onMeasure方法在控件的父元素正要放置它的子控件時調用.它會問一個問題,「你想要用多大地方啊?」,而後傳入兩個參數——widthMeasureSpec和heightMeasureSpec.
它們指明控件可得到的空間以及關於這個空間描述的元數據.
比返回一個結果要好的方法是你傳遞View的高度和寬度到setMeasuredDimension方法裏.
接下來的代碼片斷給出瞭如何重寫onMeasure.注意,調用的本地空方法是來計算高度和寬度的.它們會譯解widthHeightSpec和heightMeasureSpec值,並計算出合適的高度和寬度值.
java代碼: 框架
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-
- int measuredHeight = measureHeight(heightMeasureSpec);
- int measuredWidth = measureWidth(widthMeasureSpec);
- setMeasuredDimension(measuredHeight, measuredWidth);
- }
-
- private int measureHeight(int measureSpec) {
-
-
- // Return measured widget height.
- }
-
- private int measureWidth(int measureSpec) {
-
- // Return measured widget width.
- }
複製代碼
邊界參數——widthMeasureSpec和heightMeasureSpec ,效率的緣由以整數的方式傳入。 ide
MeasureSpec封裝了父佈局傳遞給子佈局的佈局要求,每一個MeasureSpec表明了一組寬度和高度的要求。一個MeasureSpec由大小和模式組成。 函數
它有三種模式: 佈局
UNSPECIFIED(未指定), 父元素不對自元素施加任何束縛,子元素能夠獲得任意想要的大小; 測試
EXACTLY(徹底),父元素決定自元素的確切大小,子元素將被限定在給定的邊界裏而忽略它自己大小; this
AT_MOST(至多),子元素至多達到指定大小的值。 google
它經常使用的三個函數: idea
1.static int getMode(int measureSpec):根據提供的測量值(格式)提取模式(上述三個模式之一) spa
2.static int getSize(int measureSpec):根據提供的測量值(格式)提取大小值(這個大小也就是咱們一般所說的大小)
3.static int makeMeasureSpec(int size,int mode):根據提供的大小值和模式建立一個測量值(格式)
這個類的使用呢,一般在view組件的onMeasure方法裏面調用但也有少數例外
在它們使用以前,首先要作的是使用MeasureSpec類的靜態方法getMode和getSize來譯解,以下面的片斷所示:
java代碼:
- int specMode = MeasureSpec.getMode(measureSpec);
- int specSize = MeasureSpec.getSize(measureSpec);
複製代碼
依據specMode的值,若是是AT_MOST,specSize 表明的是最大可得到的空間;若是是EXACTLY,specSize 表明的是精確的尺寸;若是是UNSPECIFIED,對於控件尺寸來講,沒有任何參考意義。
當以EXACT方式標記測量尺寸,父元素會堅持在一個指定的精確尺寸區域放置View。在父元素問子元素要多大空間時,AT_MOST指示者會說給我最大的範圍。在不少狀況下,你獲得的值都是相同的。
在兩種狀況下,你必須絕對的處理這些限制。在一些狀況下,它可能會返回超出這些限制的尺寸,在這種狀況下,你可讓父元素選擇如何對待超出的View,使用裁剪仍是滾動等技術。
接下來的框架代碼給出了處理View測量的典型實現:
java代碼:
- @Override
-
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-
- int measuredHeight = measureHeight(heightMeasureSpec);
-
- int measuredWidth = measureWidth(widthMeasureSpec);
-
- setMeasuredDimension(measuredHeight, measuredWidth);
-
- }
-
- private int measureHeight(int measureSpec) {
-
- int specMode = MeasureSpec.getMode(measureSpec);
- int specSize = MeasureSpec.getSize(measureSpec);
-
- // Default size if no limits are specified.
-
- int result = 500;
- if (specMode == MeasureSpec.AT_MOST){
-
- // Calculate the ideal size of your
- // control within this maximum size.
- // If your control fills the available
- // space return the outer bound.
-
- result = specSize;
- }
- else if (specMode == MeasureSpec.EXACTLY){
-
- // If your control can fit within these bounds return that value.
- result = specSize;
- }
-
- return result;
- }
-
- private int measureWidth(int measureSpec) {
- int specMode = MeasureSpec.getMode(measureSpec);
- int specSize = MeasureSpec.getSize(measureSpec);
-
- // Default size if no limits are specified.
- int result = 500;
- if (specMode == MeasureSpec.AT_MOST){
- // Calculate the ideal size of your control
- // within this maximum size.
- // If your control fills the available space
- // return the outer bound.
- result = specSize;
- }
-
- else if (specMode == MeasureSpec.EXACTLY){
- // If your control can fit within these bounds return that value.
-
- result = specSize;
- }
-
- return result;
- }