如果ScrollView嵌套ListView后,ListView只会显示一个item的高度,如下图:

原因是ScrollView在测量的时候改变了子view(即ListVIew)的测量模式,贴代码:
//scrollview的onmeasure()方法
if (child.getMeasuredHeight() < desiredHeight) {
final int childWidthMeasureSpec = getChildMeasureSpec(
widthMeasureSpec, widthPadding, lp.width);
final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
desiredHeight, MeasureSpec.EXACTLY);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
整个测量过程也是一次根节点开始的遍历过程,测量过程中父布局需要告诉子布局具体的模式和宽高值,对子布局来说是一种约束,子布局需要在规定的范围内进行绘制。
因此也就是scrollview改变了listview的测量模式和值(log得出Listview使用的是UNSPECIFIED模式),所以Listview最终只显示一个item的高度。
解决方法:
重写ListView的onmeasure()方法:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// int mode = MeasureSpec.getMode(heightMeasureSpec);
// switch (mode) {
// case MeasureSpec.UNSPECIFIED:
// Log.i("MyListVIew", "UNSPECIFIED");
// break;
// case MeasureSpec.EXACTLY:
// Log.i("MyListVIew", "EXACTLY");
// break;
// case MeasureSpec.AT_MOST:
// Log.i("MyListVIew", "AT_MOST");
// break;
// }
int i = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, i);
}
int i = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);这个代码的含义:
设置一个指定的尺寸大小和指定模式的MeasureSpec值,第一个参数是设置指定的值,第二个参数是设定模式。
Integer.MAX_VALUE >> 2的含义:
MeasureSpec是一个int值,int占4个字节,32位,最高的两位代表的是模式,后面的30位值代表的是尺寸大小。因此Integer.MAX_VALUE >> 2就是最大的数值右移两位(去掉代表模式的位),后面指定模式,刚好就组成了一个Measurespec值。
意思就是在父类最大的范围内去绘制Listview。
网友评论