項目中要作一個下拉縮放圖片的效果,搜索了下github上面,找到了兩個方案。html
https://github.com/Frank-Zhu/PullZoomViewandroid
這個庫原本作的還能夠,不過有個缺陷就是,當scroolview滑動到底部,再向上拉動,會致使放大效果不連續,須要從新釋放,再次下拉,這對於追求細節的我來講,不可忍受。看了半天他的代碼,感受他的實現方式很難修改成我想要的效果,後來就放棄了。git
https://github.com/Gnod/ParallaxListViewgithub
這個自定義view寫的筆記簡單,也很容易看懂,同時避免了上面那個庫的問題,因此經過簡單的改造,我修改爲爲ScrollView的方式。可是同時也碰到一個問題,那就是當ScrollView中包含的view設置了OnClickListner事件的時候,觸摸事件的傳遞會出現問題。致使滑動出現異常。ide
下面就是我修改後的項目地址函數
下面主要說明下,我在修復bug的時候的思路。htm
首先看下具體問題:blog
當scrollview 中的元素未佔滿scrollview的時候,在scrollivew的onInterceptTouchEvent方法中事件
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { //中間代碼省略 /* * Don't try to intercept touch if we can't scroll anyway. */ if (getScrollY() == 0 && !canScrollVertically(1)) { return false; } //中間代碼省略 }
有一個canScrollVertically的判斷,用來返回scrollview的內容是否撐滿,因此當scrollview中的元素未佔滿的時候,這裏直接返回false,scrollview的觸摸事件沒有截獲,直接交給了子view處理,而這個時候,子view又設置了click事件,對觸摸進行了消費,因此scrollivew沒法響應下拉的手勢操做了。
對於這種觸摸衝突的問題,以前看《android藝術開發探索》時候,有過了解,無非就是兩個,一個外部攔截,一個內部攔截。想到scrollview中的元素可能會嵌套不少類型的。因此內部攔截的方式,可能工做量很大,須要每一個View作處理。因此初步鎖定了外部攔截方式。
剛開始的思路也很清晰,就是當向下滑動的距離大於了TouchSlop時候,就截獲事件,不向下傳遞,若是是點擊的時候,則直接傳遞到下面的view進行處理。
@Override public boolean onInterceptTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: xFirst = event.getX(); yFirst = event.getY(); mIsIntercept = false; case MotionEvent.ACTION_MOVE: xDistance = event.getX()-xFirst; yDistance = event.getY()-yFirst; if(Math.abs(yDistance)>mTouchSlop){ mIsIntercept = true; }else { mIsIntercept = false; } break; case MotionEvent.ACTION_UP: mIsIntercept = false; break; default: break; } return mIsIntercept; } @Override public boolean canScrollVertically(int direction) { return true; }
但是當這樣寫以後,老是會拋一個錯誤,Invalid pointerId=-1 in onTouchEvent,到源碼裏面看,這個錯是
@Override public boolean onTouchEvent(MotionEvent event) { Log.e("scrollview",event.getAction()+""); touchListener.onTouchEvent(event); return super.onTouchEvent(event); }
是調用super.onTouchEvent(event)的時候拋出來的,再次查看源碼,原來是scrollview裏面的一個變量沒有賦值,本來的賦值操做是在onInterceptTouchEvent中,可是這個函數已經被咱們重寫,那怎麼辦呢。後來想到,假如我在ACTION_DWON裏面,先調用下surper.onInterceptTouchEvent(event),將變量賦值,那不就ok了,因此最後的代碼結果是
@Override public boolean onInterceptTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: xFirst = event.getX(); yFirst = event.getY(); mIsIntercept = false; //這句話是關鍵 super.onInterceptTouchEvent(event); case MotionEvent.ACTION_MOVE: xDistance = event.getX()-xFirst; yDistance = event.getY()-yFirst; if(Math.abs(yDistance)>mTouchSlop){ mIsIntercept = true; }else { mIsIntercept = false; } break; case MotionEvent.ACTION_UP: mIsIntercept = false; break; default: break; } return mIsIntercept; } @Override public boolean canScrollVertically(int direction) { return true; }
同時咱們也將canScrollVertically這個函數直接返回true,即不讓super.onInterceptTouchEvent(event);調用的時候直接返回false
這樣我就完美的解決了事件的分發處理與Invalid pointerId=-1 in onTouchEvent這個問題。
上述的問題,大概通過了兩天的各類嘗試,才獲得結果。並且靈感是在回家以後,不經意的一個瞬間,想到的,因此有時候,遇到問題,本身能夠暫時先放一放,換個時間思惟角度也許就大不同,問題也就迎刃而解。