在View.Java中的定義:
public final void measure(int widthMeasureSpec,int heightMeasureSpec){
...
onMeasure
...
}
protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
public static int getDefaultSize(int size, int measureSpec) {
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED: //未指定
result = size;
break;
case MeasureSpec.AT_MOST: //至多
case MeasureSpec.EXACTLY: //精確
result = specSize;
break;
}
return result;
}
在ViewGroup中:
protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
final int size = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < size; ++i) {
final View child = children[i];
if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
measureChild(child, widthMeasureSpec, heightMeasureSpec);
}
}
}
protected void measureChild(View child, int parentWidthMeasureSpec,
int parentHeightMeasureSpec) {
final LayoutParams lp = child.getLayoutParams();
final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
mPaddingLeft + mPaddingRight, lp.width);
final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
mPaddingTop + mPaddingBottom, lp.height);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
protected void measureChildWithMargins(View child,
int parentWidthMeasureSpec, int widthUsed,
int parentHeightMeasureSpec, int heightUsed) {
final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
+ widthUsed, lp.width);
final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
+ heightUsed, lp.height);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
說明:
- measure是final修飾的方法,不可被重寫。
在外部調(diào)用時,直接調(diào)用view.measure(int wSpec, int hSpec)。
measure中調(diào)用了onMeasure。
自定義view時,重寫onMeasure即可。
2.MeasureSpec 這是一個含mode和size的結(jié)合體,不需要我們來具體的關(guān)心。
當(dāng)在測量時,可以調(diào)用MeasureSpec.getSize|getMode 得到相應(yīng)的size和mode。
然后使用MeasureSpec.makeMeasureSpec(size,mode); 來創(chuàng)建MeasureSpec對象。
那么mode是怎么來的呢?是根據(jù)使用該自定義view時的layoutWith|height參數(shù)決定的,所以不能自己隨便new一個。
而size可以自己指定,也可以直接使用 measureSpec.getSize。
3.如果是一個View,重寫onMeasure時要注意:
如果在使用自定義view時,用了wrap_content。那么在onMeasure中就要調(diào)用setMeasuredDimension,
來指定view的寬高。如果使用的fill_parent或者一個具體的dp值。那么直接使用super.onMeasure即可。
4.如果是一個ViewGroup,重寫onMeasure時要注意:
首先,結(jié)合上面兩條,來測量自身的寬高。
然后,需要測量子View的寬高。
測量子view的方式有:
getChildAt(int index).可以拿到index上的子view。
通過getChildCount得到子view的數(shù)目,再循環(huán)遍歷出子view。
接著,subView.measure(int wSpec, int hSpec); //使用子view自身的測量方法
或者調(diào)用viewGroup的測量子view的方法:
//某一個子view,多寬,多高, 內(nèi)部加上了viewGroup的padding值
measureChild(subView, int wSpec, int hSpec);
//所有子view 都是 多寬,多高, 內(nèi)部調(diào)用了measureChild方法
measureChildren(int wSpec, int hSpec);
//某一個子view,多寬,多高, 內(nèi)部加上了viewGroup的padding值、margin值和傳入的寬高wUsed、hUsed
measureChildWithMargins(subView, intwSpec, int wUsed, int hSpec, int hUsed);