如果LinearLayout的宽度是wrap_content,里面TextView 的宽度是match_parent,那么TextView和LinearLayout的宽度测量要怎么测量,
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="100dp"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="100dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
widthMeasureSpec 与 heightMeasureSpec是一个int型的变量,高2位用来封装MeasureMode,剩下的封装parent能够容纳的最大值,MeasureSpec.getMode(widthMeasureSpec),MeasureSpec.getSize(widthMeasureSpec)。如果ViewGroup的宽度是EXACTLY(match_parent,100dp)直接使用固定值来测量,就是100dp或者是parent的宽度,如果是wrap_content,就需要测量childView的宽度,测量时包括childView的排列方(LinearLayout,RelativeLayout等)。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int count = getChildCount();
int maxHeight = 0;
int maxWidth = 0;
int measuredChildState = 0;
// Find rightmost and bottom-most child
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
measureChild(child, widthMeasureSpec, heightMeasureSpec);
maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
measuredChildState = combineMeasuredStates(measuredChildState,
child.getMeasuredState());
}
}
// Account for padding too
maxWidth += mPaddingLeft + mPaddingRight;
maxHeight += mPaddingTop + mPaddingBottom;
// Check against our minimum height and width
maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, measuredChildState),
resolveSizeAndState(maxHeight, heightMeasureSpec,
measuredChildState<<MEASURED_HEIGHT_STATE_SHIFT));
}
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);
}
计算childView的时候,传递进了parentWidthMeasureSpec,我们继续往下跟。
public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
int specMode = MeasureSpec.getMode(spec);
int specSize = MeasureSpec.getSize(spec);
int size = Math.max(0, specSize - padding);
int resultSize = 0;
int resultMode = 0;
switch (specMode) {
case MeasureSpec.AT_MOST:
if (childDimension >= 0) {
// Child wants a specific size... so be it
resultSize = childDimension;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.MATCH_PARENT) {
// Child wants to be our size, but our size is not fixed.
// Constrain child to not be bigger than us.
resultSize = size;
resultMode = MeasureSpec.AT_MOST;
} else if (childDimension == LayoutParams.WRAP_CONTENT) {
// Child wants to determine its own size. It can't be
// bigger than us.
resultSize = size;
resultMode = MeasureSpec.AT_MOST;
}
break;
...
}
回到刚才的问题上,LinearLayout的宽度是wrap_content对应AT_MOST,childDimension对应MATCH_PARENT,所以在这里即使设置了TextView的宽度是match_parent,实际上系统帮我们转换成了wrap_content模式,宽度是parent的specSize,parent的宽度实际上是他的parent的能给他的最大宽度。
]
网友评论