項(xiàng)目中需要一個(gè) 股票列表 橫向縱向一起聯(lián)動(dòng)的效果,如下圖
(借用http://blog.csdn.net/chengxu_hou/article/details/62422027 的圖)

在github里面尋覓很久,找到了https://github.com/monkeyLittleMonkey/ListViewHorizontalScrollDemo
反編譯了騰訊自選股的apk,發(fā)現(xiàn)兩者實(shí)現(xiàn)是差不多的,都是ListView+自定義的HorizontalScrollView為核心,加上外部嵌套攔截的LinearLayout,雖然只有8stars,沒有closed Issue,項(xiàng)目緊,我還是用了。
然后開始爬坑。
沒有下拉刷新? 加之...
頭部Header區(qū)域 無法點(diǎn)擊? 改造攔截的LinearLayout,onInterceptTouchEvent return false
直到... 差不多 快完成了,發(fā)現(xiàn)... 埃? 怎么左右 無法滑動(dòng)了? 剛剛開始的時(shí)候還能滑,咋寫完了 不能滑了?
先是一通胡亂的嘗試...
分析了一下 我的項(xiàng)目與 ListViewHorizontalScrollDemo的區(qū)別
1.控件是通過 橫滑listview--帶動(dòng)頭部header的HorizontalScrollView滑動(dòng),然后頭部的header里有一個(gè)observor 持有當(dāng)前頁面所有item的HorizontalScrollView引用,因此可以帶動(dòng)當(dāng)前頁面所有HorizontalScrollView的橫向滑動(dòng)。既然滑動(dòng)事件被攔截了,那么可能是頭部設(shè)置了OnClick事件引起的
去掉點(diǎn)擊事件。。
不行
2.難道不成是XListView的下拉刷新攔截了事件? 去掉下拉刷新。
不行
3.我設(shè)置了TouchDelegate增加點(diǎn)擊區(qū)域,難道是這個(gè)? 這個(gè)的具體實(shí)現(xiàn)源碼也懶得看了,先去掉試試
不行
4.取消掉頭部的改造攔截的LinearLayout..
不行
5.難道布局xml里的 focusable ,blocksDescendants設(shè)置了也影響了?去掉去掉
不行
6.難道我在修改自定義HorizontalScrollView的注釋的時(shí)候刪掉了 某行代碼?
打開svn提交記錄 仔細(xì)比對(duì)。
沒有
7.我覺得 我整個(gè)項(xiàng)目已經(jīng)改造得跟github的demo一樣了,demo 可以橫向滑動(dòng),我依然不行。
8.我檢出了項(xiàng)目?jī)商烨皠傞_始增加此自定義HorizontalScrollView的版本。運(yùn)行...是可以橫滑的
但是這兩天我提交十多處涉及view事件處理的代碼,我沒辦法知道是哪行影響了。
還好是有Log的
HorizontalScrollView Invalid pointerId=-1 in onTouchEvent
我發(fā)現(xiàn)了我的項(xiàng)目與demo不同的是,我一旦觸摸橫向滑動(dòng),會(huì)報(bào)這個(gè)錯(cuò)誤。
很大程度不能橫向滑動(dòng)與這個(gè)錯(cuò)誤有關(guān)。
于是根據(jù)錯(cuò)誤搜索到了一篇相似場(chǎng)景的文章:
http://blog.csdn.net/a405942873/article/details/40264685
大致看了一下,他是HorizontalScrollView 里嵌套了一個(gè)類似viewpager的view。然后滑動(dòng)報(bào)錯(cuò),然后那位博主通過查看源碼 發(fā)現(xiàn)是:
由于沒有調(diào)用 super.onInterceptTouchEvent(); 造成 mActivePointerIdactivePointerIndex的值不能正確獲取。 導(dǎo)致父類 onTouchEvent取值錯(cuò)誤,最終 onTouchEvent不能正確執(zhí)行。 解決方法: 解決方法很簡(jiǎn)單,只要在重寫過的 onInterceptTouchEvent里面 添加 super.onInterceptTouchEvent();既可。
很明顯他的出錯(cuò)場(chǎng)景雖然類似,但是確實(shí)是不同。且,demo中本來就沒有調(diào)用
super.onInterceptTouchEvent()一樣能滑動(dòng)。
10.但是抱著僥幸心理的我還是蠢呵呵的去加了一行super.onInterceptTouchEvent()
---ok,果然是依然不行。
此時(shí)已經(jīng)差不多浪費(fèi)了一天的時(shí)間,其實(shí)我早就應(yīng)該覺悟,早就應(yīng)該跟這個(gè)博主一樣去debug 源碼 而不是 到處亂猜了。
然而一是感覺時(shí)間緊,公司沒有谷歌親兒子Nexus機(jī),也沒空去弄 API 25的模擬器來DEBUG。
還是拿一個(gè)比較新的Android 6.0 小米機(jī) 來Debug HorizontalScrollView把

大致代碼行號(hào)雖然相差很多,但不至于太離譜。
通過我的項(xiàng)目與demo 的debug對(duì)比發(fā)現(xiàn),確實(shí)是在調(diào)用 onTouchEvent的時(shí)候,我的項(xiàng)目mActivePointerId=-1 而demo里的mActivePointerId=0
大致查了一下,mActivePointerId的賦值有好幾處,onInterceptTouchEvent和onTouchEvent里都有賦值。但是小米手機(jī)與源碼不一致,我也沒法精確確定到底源碼里哪處代碼影響了HorizontalScrollView里哪個(gè)方法對(duì)mActivePointerId的賦值。
那只能玩暴力的了。我在自定義的HorizontalScrollView的onTouchEvent里增加了
int mActivePointerId = (int) getFieldValue(this, "mActivePointerId");
if (mActivePointerId==-1){
setFieldValue(this,"mActivePointerId",0);
}
getFieldValue,setFieldValue為反射工具類方法
反射強(qiáng)制修改mActivePointerId的值為0。
11.這次確實(shí)證明 比較接近真相了。確實(shí)可以滑動(dòng)了。但是,當(dāng)我手指觸摸item的時(shí)候,item會(huì)跳一下,然后再開始隨著手指滑動(dòng)。因此我這么改還是不行。猜測(cè)大概是DOWN事件的坐標(biāo)沒有記錄下來傳遞給HorizontalScrollView
我覺得我真的早就應(yīng)該拿模擬器精確來DEBUG源碼了...
我早就應(yīng)該理解...
磨刀不誤砍柴工這句古訓(xùn)背后所飽含的...
古人對(duì)生活的深刻理解和感悟...
我在下班前下載好API25 arm 的image... 得了,還是回家debug 源碼吧。
運(yùn)行模擬器,運(yùn)行demo...滑動(dòng)...
ok.API一致源碼一致debug起來真是爽,再也不用亂猜了。發(fā)現(xiàn)是:

ACTION_DOWN的時(shí)候mActivePointerId進(jìn)行了賦值,之后就一直是0 了。
開始運(yùn)行我的項(xiàng)目,矮??HorizontalScrollView一開始接收到的時(shí)間就是MOVE,模擬器有問題?? 再試,還是只有MOVE,MOVE中沒有mActivePointerId進(jìn)行賦值的代碼。
Finally,debug源碼僅僅5分鐘,我就終于知道是DOWN事件沒有傳遞給HorizontalScrollView導(dǎo)致了mActivePointerId沒有被賦值 一直報(bào)錯(cuò)。。
那么我瞬間就想到了... 我在item條目的convertVIew設(shè)置的點(diǎn)擊事件(onClickListener)是不是攔截了DOWN?
媽蛋,去掉了那么多代碼,怎么沒想到這里。去掉之....
12.萬萬沒想到,只花了10分鐘debug源碼,我就終于還是解決了這個(gè)問題?;瑒?dòng)起來非常的smooth...
那么convertVIew點(diǎn)擊事件去掉了,我哪設(shè)置點(diǎn)擊事件去呢。
listview.setonItemCLickListener...的實(shí)現(xiàn)似乎是與onClickListener不同的,試試,發(fā)現(xiàn)可行。我才終于想起來 反編譯騰訊自選股apk后發(fā)現(xiàn)在activity里面listview.setonItemCLickListener而不是在adapter里面對(duì)convertView 進(jìn)行setOnClickListener確實(shí)是有原因的。。。
啥也不說了,我決定 想辦法刷一個(gè)原生的andriod系統(tǒng)來debug in order to SAVING LIFE。