项目中需要一个 股票列表 横向纵向一起联动的效果,如下图
(借用http://blog.csdn.net/chengxu_hou/article/details/62422027 的图)
在github里面寻觅很久,找到了https://github.com/monkeyLittleMonkey/ListViewHorizontalScrollDemo
反编译了腾讯自选股的apk,发现两者实现是差不多的,都是ListView+自定义的HorizontalScrollView为核心,加上外部嵌套拦截的LinearLayout,虽然只有8stars,没有closed Issue,项目紧,我还是用了。
然后开始爬坑。
没有下拉刷新? 加之...
头部Header区域 无法点击? 改造拦截的LinearLayout,onInterceptTouchEvent return false
直到... 差不多 快完成了,发现... 埃? 怎么左右 无法滑动了? 刚刚开始的时候还能滑,咋写完了 不能滑了?
先是一通胡乱的尝试...
分析了一下 我的项目与 ListViewHorizontalScrollDemo的区别
1.控件是通过 横滑listview--带动头部header的HorizontalScrollView滑动,然后头部的header里有一个observor 持有当前页面所有item的HorizontalScrollView引用,因此可以带动当前页面所有HorizontalScrollView的横向滑动。既然滑动事件被拦截了,那么可能是头部设置了OnClick事件引起的
去掉点击事件。。
不行
2.难道不成是XListView的下拉刷新拦截了事件? 去掉下拉刷新。
不行
3.我设置了TouchDelegate增加点击区域,难道是这个? 这个的具体实现源码也懒得看了,先去掉试试
不行
4.取消掉头部的改造拦截的LinearLayout..
不行
5.难道布局xml里的 focusable ,blocksDescendants设置了也影响了?去掉去掉
不行
6.难道我在修改自定义HorizontalScrollView的注释的时候删掉了 某行代码?
打开svn提交记录 仔细比对。
没有
7.我觉得 我整个项目已经改造得跟github的demo一样了,demo 可以横向滑动,我依然不行。
8.我检出了项目两天前刚开始增加此自定义HorizontalScrollView的版本。运行...是可以横滑的
但是这两天我提交十多处涉及view事件处理的代码,我没办法知道是哪行影响了。
还好是有Log的
HorizontalScrollView Invalid pointerId=-1 in onTouchEvent
我发现了我的项目与demo不同的是,我一旦触摸横向滑动,会报这个错误。
很大程度不能横向滑动与这个错误有关。
于是根据错误搜索到了一篇相似场景的文章:
http://blog.csdn.net/a405942873/article/details/40264685
大致看了一下,他是HorizontalScrollView 里嵌套了一个类似viewpager的view。然后滑动报错,然后那位博主通过查看源码 发现是:
由于没有调用 super.onInterceptTouchEvent(); 造成 mActivePointerIdactivePointerIndex的值不能正确获取。 导致父类 onTouchEvent取值错误,最终 onTouchEvent不能正确执行。 解决方法: 解决方法很简单,只要在重写过的 onInterceptTouchEvent里面 添加 super.onInterceptTouchEvent();既可。
很明显他的出错场景虽然类似,但是确实是不同。且,demo中本来就没有调用
super.onInterceptTouchEvent()一样能滑动。
10.但是抱着侥幸心理的我还是蠢呵呵的去加了一行super.onInterceptTouchEvent()
---ok,果然是依然不行。
此时已经差不多浪费了一天的时间,其实我早就应该觉悟,早就应该跟这个博主一样去debug 源码 而不是 到处乱猜了。
然而一是感觉时间紧,公司没有谷歌亲儿子Nexus机,也没空去弄 API 25的模拟器来DEBUG。
还是拿一个比较新的Android 6.0 小米机 来Debug HorizontalScrollView把
大致代码行号虽然相差很多,但不至于太离谱。
通过我的项目与demo 的debug对比发现,确实是在调用 onTouchEvent的时候,我的项目mActivePointerId=-1 而demo里的mActivePointerId=0
大致查了一下,mActivePointerId的赋值有好几处,onInterceptTouchEvent和onTouchEvent里都有赋值。但是小米手机与源码不一致,我也没法精确确定到底源码里哪处代码影响了HorizontalScrollView里哪个方法对mActivePointerId的赋值。
那只能玩暴力的了。我在自定义的HorizontalScrollView的onTouchEvent里增加了
int mActivePointerId = (int) getFieldValue(this, "mActivePointerId");
if (mActivePointerId==-1){
setFieldValue(this,"mActivePointerId",0);
}
getFieldValue,setFieldValue为反射工具类方法
反射强制修改mActivePointerId的值为0。
11.这次确实证明 比较接近真相了。确实可以滑动了。但是,当我手指触摸item的时候,item会跳一下,然后再开始随着手指滑动。因此我这么改还是不行。猜测大概是DOWN事件的坐标没有记录下来传递给HorizontalScrollView
我觉得我真的早就应该拿模拟器精确来DEBUG源码了...
我早就应该理解...
磨刀不误砍柴工这句古训背后所饱含的...
古人对生活的深刻理解和感悟...
我在下班前下载好API25 arm 的image... 得了,还是回家debug 源码吧。
运行模拟器,运行demo...滑动...
ok.API一致源码一致debug起来真是爽,再也不用乱猜了。发现是:
ACTION_DOWN的时候mActivePointerId进行了赋值,之后就一直是0 了。
开始运行我的项目,矮??HorizontalScrollView一开始接收到的时间就是MOVE,模拟器有问题?? 再试,还是只有MOVE,MOVE中没有mActivePointerId进行赋值的代码。
Finally,debug源码仅仅5分钟,我就终于知道是DOWN事件没有传递给HorizontalScrollView导致了mActivePointerId没有被赋值 一直报错。。
那么我瞬间就想到了... 我在item条目的convertVIew设置的点击事件(onClickListener)是不是拦截了DOWN?
妈蛋,去掉了那么多代码,怎么没想到这里。去掉之....
12.万万没想到,只花了10分钟debug源码,我就终于还是解决了这个问题。滑动起来非常的smooth...
那么convertVIew点击事件去掉了,我哪设置点击事件去呢。
listview.setonItemCLickListener...的实现似乎是与onClickListener不同的,试试,发现可行。我才终于想起来 反编译腾讯自选股apk后发现在activity里面listview.setonItemCLickListener而不是在adapter里面对convertView 进行setOnClickListener确实是有原因的。。。
啥也不说了,我决定 想办法刷一个原生的andriod系统来debug in order to SAVING LIFE。