问题:
ScrollView里面嵌套Listview,ListView为什么只显示第一行的高度?
解析源码:
在listview的onMeasure方法中可以看到,当测量模式为UNSPECIFIED的时候只测量一行的高度,测量模式为AT_MOST的时候才是测量整个listview的高度
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);
}
所以我们就可以猜想,是不是listview的父容器Scrollview传给listview的测量模式是UNSPECIFIED呢?
经过在Scrollview源码中一番查找,我们可以找到Scrollvie重写了measureChildWithMargins方法,并给子view设置了测量模式
@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 childHeightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(
MeasureSpec.getSize(parentHeightMeasureSpec), MeasureSpec.UNSPECIFIED);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
解决方法:
1、自定义listview,重写onMeasure方法
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int heightSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2 ,MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightSpec);
}
2、在Scrollview的onMeasure方法中,mFillViewport的默认值是false,直接return了,没法设置child的高度,所以可以在xml中设置android:fillViewport=”true”,把listview的高度设置成Scrollview的高度减去padding