在自定義View和ViewGroup的時(shí)候,我們經(jīng)常會遇到int型的MeasureSpec來表示一個(gè)組件的大小,這個(gè)變量里面不僅有組件的尺寸大小,還有大小的模式。
這個(gè)大小的模式,有點(diǎn)難以理解。在系統(tǒng)中組件的大小模式有三種:
精確模式(MeasureSpec.EXACTLY) 在這種模式下,尺寸的值是多少,那么這個(gè)組件的長或?qū)捑褪嵌嗌?。最大模式(MeasureSpec.AT_MOST) 這個(gè)也就是父組件,能夠給出的最大的空間,當(dāng)前組件的長或?qū)捵畲笾荒転檫@么大,當(dāng)然也可以比這個(gè)小。未指定模式(MeasureSpec.UNSPECIFIED) 這個(gè)就是說,當(dāng)前組件,可以隨便用空間,不受限制。可能有很多人想不通,一個(gè)int型整數(shù)怎么可以表示兩個(gè)東西(大小模式和大小的值),一個(gè)int類型我們知道有32位。而模式有三種,要表示三種狀 態(tài),至少得2位二進(jìn)制位。于是系統(tǒng)采用了最高的2位表示模式。如圖: 
很多人一遇到位操作頭就大了,為了操作簡便,于是系統(tǒng)給我提供了一個(gè)MeasureSpec工具類。 這個(gè)工具類有四個(gè)方法和三個(gè)常量(上面所示)供我們使用:
//這個(gè)是由我們給出的尺寸大小和模式生成一個(gè)包含這兩個(gè)信息的int變量,這里這個(gè)模式這個(gè)參數(shù),傳三個(gè)常量中的一個(gè)。public static int makeMeasureSpec(int size, int mode)//這個(gè)是得到這個(gè)變量中表示的模式信息,將得到的值與三個(gè)常量進(jìn)行比較。public static int getMode(int measureSpec)//這個(gè)是得到這個(gè)變量中表示的尺寸大小的值。public static int getSize(int measureSpec)//把這個(gè)變量里面的模式和大小組成字符串返回來,方便打日志 public static String toString(int measureSpec)MeasureSpec.EXACTLY:使用measureSpec中size的值作為寬高的精確值 當(dāng)我們將控件的layout_width或layout_height指定為具體數(shù)值時(shí)如andorid:layout_width=”50dip”,或者為FILL_PARENT是,都是控件大小已經(jīng)確定的情況,都是精確尺寸。MeasureSpec.AT_MOST:使用measureSpec中size的值作為最大值,采用不超過這個(gè)值的最大允許值 當(dāng)控件的layout_width或layout_height指定為WRAP_CONTENT時(shí),控件大小一般隨著控件的子空間或內(nèi)容進(jìn)行變化,此時(shí)控件尺寸只要不超過父控件允許的最大尺寸即可。因此,此時(shí)的mode是AT_MOST,size給出了父控件允許的最大尺寸。MeasureSpec.UNSPECIFIED是未指定尺寸,這種情況不多以scrollview嵌套listview為例,我們重寫onMesure方法:
@OverridePRotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.makeMeasureSpec(1000>>2,MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, width);}1000的二進(jìn)制:1111101000 右移2位后:11111010,十進(jìn)制為:250
這樣就指定了listview的高度為250px以內(nèi)的最大允許值(一般就是250)
把AT_MOST改為EXACTLY,則精確指定listview高度值為250px,如果listview內(nèi)容全部顯示的高度為500px(大于250px),那么當(dāng)measureSpec中size的值為250px(小于500px)時(shí),效果是一樣的
如果設(shè)置的measureSpec中size的值大于listview內(nèi)容全部顯示的高度,那么設(shè)置成AT_MOST時(shí),最多顯示listview內(nèi)容全部顯示的高度,而EXACTLY還是顯示measureSpec中size的值,所以EXACTLY在這種情況下,后面會留有空白高度(measureSpec中size的值大于listview內(nèi)容全部顯示的高度的部分顯示為空白)
所以,一般這樣寫可以讓listview正確測量:
int width = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE>>2,MeasureSpec.AT_MOST);MAX_VALUE右移2位后,即使不是最大整數(shù)了,listview的高度也一般不可能超過它 第一個(gè)參數(shù)有個(gè)最大值的限制:1073741823(二進(jìn)制的30個(gè)1),MAX_VALUE是1個(gè)0加上31個(gè)1(二進(jìn)制),所以也可以右移1位,但是由于最前面兩位表示mode,而不是size,所有右移1位和右移2位是一樣的(前面兩位的值都會被mode的代碼覆蓋)
新聞熱點(diǎn)
疑難解答