android一個下拉放大庫bug的解決過程及思考


android一個下拉放大庫bug的解決過程及思考

起因

項目中要做一個下拉縮放圖片的效果,搜索了下github上面,找到了兩個方案。

  • https://github.com/Frank-Zhu/PullZoomView

    這個庫本來做的還可以,不過有個缺陷就是,當scroolview滑動到底部,再向上拉動,會導致放大效果不連續,需要重新釋放,再次下拉,這對於追求細節的我來說,不可忍受。看了半天他的代碼,感覺他的實現方式很難修改為我想要的效果,后來就放棄了。

  • https://github.com/Gnod/ParallaxListView

    這個自定義view寫的筆記簡單,也很容易看懂,同時避免了上面那個庫的問題,所以通過簡單的改造,我修改成為ScrollView的方式。但是同時也碰到一個問題,那就是當ScrollView中包含的view設置了OnClickListner事件的時候,觸摸事件的傳遞會出現問題。導致滑動出現異常。

下面就是我修改后的項目地址

PullToZoomScrollView

下面主要說明下,我在修復bug的時候的思路。

首先看下具體問題:

當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這個問題。

總結

上述的問題,大概經過了兩天的各種嘗試,才得到結果。而且靈感是在回家之后,不經意的一個瞬間,想到的,所以有時候,遇到問題,自己可以暫時先放一放,換個時間思維角度也許就大不一樣,問題也就迎刃而解。

轉載請注明出處
http://www.cnblogs.com/gaoteng/p/5485634.html

http://www.gaotenglife.com/?p=382


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM