概述
ScrollView内镶嵌ListView会出现显示不全(只显示一个Item)的问题,这里我们要回答具体原因和解决方案。
问题分析
先看关于测量View的几个参数:
在ScrollView中添加ListView,那么ScrollView就是父View,ListView是子View。先看ScrollView的onMeasure()的源码:
ScrollView.class:
父View:
FrameLaout.class :
到这里就需要看下measureChildWithMargins方法了,点进去之后发现在ViewGroup里面,这里对子View进行了测量处理
ViewGroup.class:
因为他们的继承关系是:ScrollView继承FrameLaout继承ViewGroup,而SrcollView的子View是ListView,所以重点看下ScrollVIew的measureChildWithMargins方法。如下:
ScrollView.class :
这句很关键,它给所有的子View的MODE设置为MeasureSpec.UNSPECIFIED
而在ListView的onMeasure中可以看到:
ListView.class:
这里可以看到在MODE是MeasureSpec.UNSPECIFIED的情况下,只计算了一个View的高度
这就是为什么只看到一个Item的原因。
解决方案
当MODE是MeasureSpec.UNSPECIFIED的情况下,只计算了一个View的高度。所以要设置MODE,当MODE是MeasureSpec.AT_MOST时会调用measureHeightOfChildren方法:
返回的是child的高度,这就没问题,那么如何制定MODE的值为AT_MOST呢
这里借用了网上的解决方案,继承ListView,重写onMeasure()方法:
MeasureSpec.class:
之后就会调用父类的onMeasure方法,重新测量。
为什么会是Integer.MAX_VALUE>>2呢?
我们需要的是returnedHeight,所以该if不能让它成立,要给maxHeight一个最大的值,第一个参数Integer.MAX_VALUE>>2,这个参数是传的一个大小值,它的大小最大值是int的最低30位的最大值,我们先取Integer.MAX_VALUE来获取int值的最大值,然后右移2位就得到这个临界值最大值了。。。恍恍惚惚。。。
总结
在ListView对Item的测量中,在MODE为UNSPECIFIED的情况下,只计算一个child的高度。而ScrollView中对所有的子View的MODE都设置为UNSPECIFIED。所以当ScrollView镶嵌了ListView,ListView成为了子View,那么就会出现显示不全的问题。