A MeasureSpec encapsulates the layout requirements passed from parent to child. Each MeasureSpec represents a requirement
for either the width or the height. A MeasureSpec is comprised of a size and a mode. There are three possible modes:
UNSPECIFIED
The parent has not imposed any constraint on the child. It can be whatever size it wants.
EXACTLY
The parent has determined an exact size for the child. The child is going to be given those bounds regardless of how big it wants to be.
AT_MOST
The child can be as large as it wants up to the specified size.
1.使用 View.resolveSize(int size,int measureSpec)
public static int resolveSize(int size, intmeasureSpec) {int result =size;int specMode =MeasureSpec.getMode(measureSpec);int specSize =MeasureSpec.getSize(measureSpec);switch(specMode) {caseMeasureSpec.UNSPECIFIED:
result=size;break;caseMeasureSpec.AT_MOST:
result=Math.min(size, specSize);break;caseMeasureSpec.EXACTLY:
result=specSize;break;
}returnresult;
}
2.源碼
public static classMeasureSpec {private static final int MODE_SHIFT = 30;private static final int MODE_MASK = 0x3 <
}public static int getMode(intmeasureSpec) {return (measureSpec &MODE_MASK);
}public static int getSize(intmeasureSpec) {return (measureSpec & ~MODE_MASK);
}}
示例:
int measureSpec = makeMeasureSpec(4, EXACTLY);
getSize(measureSpec);
getMode(measureSpec);
-----------------------makeMeasureSpec --------------------- mode+size
mode: 1000 0000 0000 0000 0000 0000 0000 000
size: 100
measureSpec: 1000 0000 0000 0000 0000 0000 0000 100
---------------getMode ---------------- MODE_MASK & measureSpec
MODE_MASK: 1100 0000 0000 0000 0000 0000 0000 0000
measureSpec: 1000 0000 0000 0000 0000 0000 0000 100
3.示例ListView.measureItem(View child)
private voidmeasureItem(View child) {
ViewGroup.LayoutParams p=child.getLayoutParams();if (p == null) {
p= newViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}int childWidthSpec =ViewGroup.getChildMeasureSpec(mWidthMeasureSpec,
mListPadding.left+mListPadding.right, p.width);int lpHeight =p.height;intchildHeightSpec;if (lpHeight > 0) {
childHeightSpec=MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
}else{
childHeightSpec= MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
}
4.重寫ListView與ScrollView 兼容:
protected voidonMeasure (int widthMeasureSpec, int heightMeasureSpec)
Parameters
widthMeasureSpec horizontal space requirements as imposed by the parent. The requirements are encoded with View.MeasureSpec.
heightMeasureSpec vertical space requirements as imposed by the parent. The requirements are encoded with View.MeasureSpec.
重寫:
public void onMeasure(int widthMeasureSpec, intheightMeasureSpec) {int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);super.onMeasure(widthMeasureSpec, expandSpec);
}
ListView
@Overrideprotected void onMeasure(int widthMeasureSpec, intheightMeasureSpec) {//Sets up mListPadding
super.onMeasure(widthMeasureSpec, heightMeasureSpec);int widthMode =MeasureSpec.getMode(widthMeasureSpec);int heightMode =MeasureSpec.getMode(heightMeasureSpec);int widthSize =MeasureSpec.getSize(widthMeasureSpec);int heightSize =MeasureSpec.getSize(heightMeasureSpec);int childWidth = 0;int childHeight = 0;
mItemCount= mAdapter == null ? 0: mAdapter.getCount();if (mItemCount > 0 && (widthMode == MeasureSpec.UNSPECIFIED ||heightMode==MeasureSpec.UNSPECIFIED)) {final View child = obtainView(0);
measureScrapChild(child,0, widthMeasureSpec);
childWidth=child.getMeasuredWidth();
childHeight=child.getMeasuredHeight();if(recycleOnMeasure()) {
mRecycler.addScrapView(child);
}
}if (widthMode ==MeasureSpec.UNSPECIFIED) {
widthSize= mListPadding.left + mListPadding.right + childWidth +getVerticalScrollbarWidth();
}if (heightMode ==MeasureSpec.UNSPECIFIED) {
heightSize= mListPadding.top + mListPadding.bottom + childHeight +getVerticalFadingEdgeLength()* 2;
}if (heightMode ==MeasureSpec.AT_MOST) {//TODO: after first layout we should maybe start at the first visible position, not 0
heightSize = measureHeightOfChildren(widthMeasureSpec, 0, NO_POSITION, heightSize, -1);
}
setMeasuredDimension(widthSize, heightSize);
mWidthMeasureSpec=widthMeasureSpec;
}