在自定義View和ViewGroup的時(shí)候冬念,我們經(jīng)常會(huì)遇到int型的MeasureSpec來表示一個(gè)組件的大小趁窃,這個(gè)變量里面不僅有組件的尺寸大小,還有大小的模式急前。
這個(gè)大小的模式醒陆,有點(diǎn)難以理解。在系統(tǒng)中組件的大小模式有三種:
1.精確模式(MeasureSpec.EXACTLY)
在這種模式下裆针,尺寸的值是多少刨摩,那么這個(gè)組件的長或?qū)捑褪嵌嗌佟?br> 2.最大模式(MeasureSpec.AT_MOST)
這個(gè)也就是父組件,能夠給出的最大的空間世吨,當(dāng)前組件的長或?qū)捵畲笾荒転檫@么大澡刹,當(dāng)然也可以比這個(gè)小。
3.未指定模式(MeasureSpec.UNSPECIFIED)
這個(gè)就是說耘婚,當(dāng)前組件罢浇,可以隨便用空間,不受限制。
可能有很多人想不通嚷闭,一個(gè)int型整數(shù)怎么可以表示兩個(gè)東西(大小模式和大小的值)攒岛,一個(gè)int類型我們知道有32位。而模式有三種凌受,要表示三種狀 態(tài)阵子,至少得2位二進(jìn)制位思杯。于是系統(tǒng)采用了最高的2位表示模式胜蛉。如圖:
最高兩位是00的時(shí)候表示"未指定模式"。即MeasureSpec.UNSPECIFIED
最高兩位是01的時(shí)候表示"'精確模式"色乾。即MeasureSpec.EXACTLY
最高兩位是11的時(shí)候表示"最大模式"誊册。即MeasureSpec.AT_MOST
很多人一遇到位操作頭就大了,為了操作簡便暖璧,于是系統(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方法:
@Override
protected 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在這種情況下颗味,后面會(huì)留有空白高度(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位是一樣的(前面兩位的值都會(huì)被mode的代碼覆蓋)。