由viewgroup传参获取widthMeasureSpec,heightMeasureSpec
主要方法getChildMeasureSpec(parentWidthMeasureSpec,...)
/**
* 遍历ViewGroup中所有的子控件,调用measuireChild测量宽高
*/
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);
}
}
}
/**
* 测量某一个child的宽高
*/
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);
}
/**
* 测量某一个child的宽高,考虑margin值
*/
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);
UNSPECIFIED:不对View大小做限制,如:ListView,ScrollView(可以造成height出现UNSPECIFIED模式)
EXACTLY:确切的大小,如:100dp或者march_parent
AT_MOST:大小不可超过某数值,如:wrap_content
width取值(textview部分源码)
//EXACTLY模式下
if (widthMode == MeasureSpec.EXACTLY) {
// Parent has told us how big to be. So be it.
width = widthSize;
}
//其他两种模式走下面逻辑
else {
if (mMaxWidthMode == EMS) {
width = Math.min(width, mMaxWidth * getLineHeight());
} else {
width = Math.min(width, mMaxWidth);
}
if (mMinWidthMode == EMS) {
width = Math.max(width, mMinWidth * getLineHeight());
} else {
width = Math.max(width, mMinWidth);
}
// Check against our minimum width
width = Math.max(width, getSuggestedMinimumWidth());
//AT_MOST模式
if (widthMode == MeasureSpec.AT_MOST) {
width = Math.min(widthSize, width);
}
}
height取值(textview部分源码)
//EXACTLY模式下
if (heightMode == MeasureSpec.EXACTLY) {
// Parent has told us how big to be. So be it.
height = heightSize;
mDesiredHeightAtMeasure = -1;
}
//其他两种模式走下面逻辑
else {
int desired = getDesiredHeight();
height = desired;
mDesiredHeightAtMeasure = desired;
//AT_MOST模式
if (heightMode == MeasureSpec.AT_MOST) {
height = Math.min(desired, heightSize);
}
}
总结,EXACTLY模式下失效,直接取设定大小;AT_MOST模式下失效,取三者(最大值,最小值,确切值)最小;
UNSPECIFIED模式下有效