一潮太、默認處理
View類默認實現(xiàn):
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
默認實現(xiàn)中丛晦,調(diào)用了setMeasuredDimension( )設(shè)置測量后的寬高,這個方法需要兩個參數(shù),也就是我們測量后的寬左驾、高信息.
二镣隶、widthMeasureSpec、heightMeasureSpec
1诡右、寬安岂、高信息
不管是重寫onMeasure還是默認的實現(xiàn)中,我們都可以看到兩個int類型值:widthMeasureSpec帆吻、heightMeasureSpec.
這兩個int類型值就是寬和高信息域那,注意:無論寬度信息(widthMeasureSpec)還是高度信息(widthMeasureSpec),都包含兩種數(shù)據(jù)------模式猜煮、大小次员,模式是根據(jù)wrap_content、match_parent王带、具體值來確定的淑蔚,大小則是根據(jù)不同模式進行計算.
2、模式
我們在xml中定義layout_width愕撰、layout_height屬性時有3種情況:
wrap_content
match_parent
具體值
寬刹衫、高信息中的模式也有三個不同的常量值:
MeasureSpec.EXACTLY
當(dāng)組件的尺寸為match_parent或具體值時用該常量值表示此時的模式
MeasureSpec.AT_MOST
當(dāng)組件的尺寸為wrap_content時用該常量值表示此時的模式
MeasureSpec.UNSPECIFIED
未指定尺寸醋寝,一般用不到
很好理解,EXACTLY譯為確定的带迟,使用match_parent表示組件大小匹配父容器音羞,而父容器本身也是一個組件,它會計算出自己的大小仓犬,我們不需要重復(fù)去計算嗅绰,所以無論是match_parent還是具體值,組件大小都是確定的婶肩,所以這兩種情況都用MeasureSpec.EXACTLY來表示.
使用wrap_content(包裹內(nèi)容)時办陷,此時組件的大小需要根據(jù)內(nèi)容確定,只要在父容器指定的最大尺寸之內(nèi)就行了律歼,用MeasureSpec.AT_MOST來表示.
而MeasureSpec.UNSPECIFIED表示父容器對子視圖不進行任何約束民镜,子視圖可以是它想要的任何大小,一般用不到.
3险毁、獲取模式制圈、大小
widthMeasureSpec、heightMeasureSpec都是一個int類型值畔况,那么一個int
怎么保存模式鲸鹦、大小這兩種數(shù)據(jù)呢?
我們都知道:int類型占用4個字節(jié)跷跪,一共32位. 而widthMeasureSpec和heightMeasureSpec的前2位代表模式馋嗜,后30位表示大小.
ok,既然知道怎么表示的吵瞻,那么我們可以通過位運算來獲取模式和大懈鸸健:
模式 int mode = widthMeasureSpec & 0x3 << 30;
大小 int size = widthMeasureSpec & ~0x3 << 30;
每次都要進行位運算很麻煩,所以系統(tǒng)提供了MeasureSpec類橡羞,這個類有3個常量(就是上面的三種模式)以及一些靜態(tài)方法:
三種模式:
MeasureSpec.EXACTLY
MeasureSpec.AT_MOST
MeasureSpec.UNSPECIFIED
方法:
public static int makeMeasureSpec(int size, int mode)
傳入尺寸大小和模式生成一個包含這兩個信息的int類型值
從一個包含模式眯停、大小的int類型值中獲取模式、大小
public static int getMode(int measureSpec)
public static int getSize(int measureSpec)
三卿泽、正方形View
public class XView extends View {
public XView(Context context) {
this(context, null);
}
public XView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public XView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = myMeasure(0, widthMeasureSpec);
int height = myMeasure(0, heightMeasureSpec);
// 和系統(tǒng)onMeasure() 方法不同的是:我添加了下面的if-else語句
if (width > height) {
width = height;
} else {
height = width;
}
setMeasuredDimension(width, height);
}
/**
*雖然寫著方法名是myMeasure莺债,但是其實這就是View類getDefaultSize()方法的源碼
*注意看文章開頭,setMeasuredDimension()需要的兩個參數(shù):寬签夭、高信息都是通過這個方法生成的
*/
private int myMeasure(int defaultValue, int measureSpec) {
int result = defaultValue;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
result = defaultValue;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}
}
上面定義了一個正方形的XView齐邦,不論XView在布局文件中的寬、高如何定義第租,顯示在界面上始終是一個正方形的View(你需要設(shè)置一個背景顏色侄旬,不然看不出效果),感興趣的可以運行查看效果.