(1)查看ListView的测量方法,关注垂直方向高度
会发现当其mode为 MeasureSpec.UNSPECIFIED时
...
final View child = obtainView(0, mIsScrap);
...
childHeight = child.getMeasuredHeight();
...
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);
}
obtainView在AbsListView里面,表示拿对应位置的item,obtainView(0, mIsScrap)表示第一item,也就是在heightMode == MeasureSpec.
UNSPECIFIED时,只测量一行的高度;而在AT_MOST时候,他会测量所有item的高度。
(2)由于子View的测量模式,是父容器传递进来的,这时候查看ScrollView的传递的测量模式
,
查看ScrollView的onMeasure方法
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
...
它会先调用父类的onMeasure方法,而父类的onMeasure会调用measureChildWithMargins,这时会发现ScrollView重写了measureChildWithMargins方法
(3)ScrollView的measureChildWithMargins方法
@Override
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 usedTotal = mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin +
heightUsed;
final int childHeightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(
Math.max(0, MeasureSpec.getSize(parentHeightMeasureSpec) - usedTotal),
MeasureSpec.UNSPECIFIED);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
可以看到,其
默认设置的Mode为MeasureSpec.
UNSPECIFIED的;
这就是为什么ScrollVIew嵌套ListView只显示一行的原因
(4)解决办法:
自定义ListView ,重写其onMeasure方法,修改其mode,将其重新设置为AT_MOST:
//Interger.Max_VALUE>>2 ,高两位是设置mode,后30位的才是高度
int heightSpec = MeasureSpec.makeMeasureSpec(Interger.Max_VALUE>>2,MeasureSpec。AT_MOST);
super.onMeasure(widhtspec,heightSpec);