问题:为什么ScrollView嵌套ListView只显示一条数据
首先看解决方法:自己写一个类继承于ListView并重新测量
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
分析原因首先,ScrollView 肯定会对子View进行测量,看下源码
ScrollView.onMeasure()->Framelayout.onMeasure()->ViewGroup.measureChildWithMargins()给子view调用的->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;
//设置子view的设置模式为UNSPECIFIED
final int childHeightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(
Math.max(0, MeasureSpec.getSize(parentHeightMeasureSpec) - usedTotal),
MeasureSpec.UNSPECIFIED);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
然后看ListView的onMeasure方法
//由刚才分析我们可以知道子view这时候走的是这里,所以会显示不全
if (heightMode == MeasureSpec.UNSPECIFIED) {
heightSize = mListPadding.top + mListPadding.bottom + childHeight +
getVerticalFadingEdgeLength() * 2;
}
//所以设置模式为AT_MOST
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);
}
setMeasuredDimension(widthSize, heightSize);
为什么大小设置为(Integer.MAX_VALUE >> 2
答:我们都知道,右边2的两位是模式,后30位是大小Integer.MAX_VALUE 的大小是2的31次方,所以将最大值向右移两位进行赋值。