ScrollView嵌套ListView,ListView为什么只显示第一行的高度

来源:互联网 发布:我的世界java是什么 编辑:程序博客网 时间:2024/05/22 17:24
(1)查看ListView的测量方法,关注垂直方向高度
会发现当其mode为 MeasureSpec.UNSPECIFIED时
...
finalView 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 voidonMeasure(intwidthMeasureSpec,intheightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
...
它会先调用父类的onMeasure方法,而父类的onMeasure会调用measureChildWithMargins,这时会发现ScrollView重写了measureChildWithMargins方法

(3)ScrollView的measureChildWithMargins方法
@Override
protected voidmeasureChildWithMargins(View child,intparentWidthMeasureSpec,intwidthUsed,
intparentHeightMeasureSpec,intheightUsed) {
finalMarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

final intchildWidthMeasureSpec =getChildMeasureSpec(parentWidthMeasureSpec,
mPaddingLeft + mPaddingRight + lp.leftMargin+ lp.rightMargin
+ widthUsed, lp.width);
final intusedTotal = mPaddingTop + mPaddingBottom + lp.topMargin+ lp.bottomMargin+
heightUsed;
final intchildHeightMeasureSpec = 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);
1 0
原创粉丝点击