初识onMeasure()——解决ScrollView内嵌ListView滑动冲突

来源:互联网 发布:b站是什么软件 编辑:程序博客网 时间:2024/06/03 15:07

引言

最近同学问了一个问题,就是ScrollView嵌套ListView时出现了冲突。上网也查阅了一些资料,各路大神也是各显神通。本着“万事以简为要”的原则,最终找到了一个超级简单而且实用的解决方法——重写ListView的onMeasure()方法。

分析

具体怎么实现呢?容我慢慢道来。
首先可以看出在onMeasure(int widthMeasureSpec, int heightMeasureSpec)方法中传递进去了2个int参数,但其并不是简单的一个int变量。从源码中发现,它们各自都包括了2个属性,分别为SIZE和MODE。

以下为源码:

<span style="font-family:Times New Roman;">        int widthMode = MeasureSpec.getMode(widthMeasureSpec);    int heightMode = MeasureSpec.getMode(heightMeasureSpec);    int widthSize = MeasureSpec.getSize(widthMeasureSpec);    int heightSize = MeasureSpec.getSize(heightMeasureSpec);</span>

从中可以看出上面的2个参数就是通过MeasureSpec.makeMeasureSpec(SIZE,MODE)得到的。其size为自定义的宽度/高度大小,Mode为测量的模式。

先看下表,然后我们来说说这个MODE究竟为何方神圣。

MeasureSpec.UNSPECIFIED

父控件对子控件无限制,大小可在布局文件自定义

MeasureSpec.EXACTLY

父控件已明确子控件大小,子控件无条件服从

MeasureSpec.AT_MOST

子控件可根据自己的实际需要自适应大小

Ps:默认使用的时第一种MODE。

由上表可以看出,onMeasure()传入的2个参数中,SIZE即为控件的大小,然而并不能就此说明该控件内容的大小刚好为所提供的SIZE这么大,因为他还需要经过MODE来计算。也就是说(以高度为例),

ActualSize=f(SIZE)

其中:ActualSize为控件内容实际所占高度;

           f()为MODE的测量模式,即MeasureSpec.getMode(heightMeasureSpec);

           SIZE为传入的SIZE,即MeasureSpec.getSize(heightMeasureSpec)

相信看到这里,大伙都应该知道下一步我们该做了什么了——重写onMeasure()

代码如下:

<span style="font-family:Times New Roman;">                @Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int expandSpec = MeasureSpec.makeMeasureSpec(SIZE,MeasureSpec.AT_MOST);super.onMeasure(widthMeasureSpec, expandSpec);}</span>

其中SIZE可以自己写,就是你预设定的最大高度。(一般就用Integer.MAX_VALUE>>2-1,也就是(1<<30)-1。至于为什么使用这个值,那是因为MeasureSpec的低30位才表示size,最大也就是(1<<30)-1),高2位表示的是SpecMode)。

这样就可以完美而简单高效地解决ScrollView内嵌ListView的冲突问题。

结束语

第一次发博客,排版亟待加强,日后会改善,这次多多见谅了。同时发现看源码原来是这么好玩的一件事,继续努力。

最后,有兴趣的还可以去关注下GridView、ExpandableListView的onMeassure()方法,我相信你的收获不会只有一点点的。



0 0
原创粉丝点击