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

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

原由

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

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

    這個庫原本作的還能夠,不過有個缺陷就是,當scroolview滑動到底部,再向上拉動,會致使放大效果不連續,須要從新釋放,再次下拉,這對於追求細節的我來講,不可忍受。看了半天他的代碼,感受他的實現方式很難修改成我想要的效果,後來就放棄了。git

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

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

下面就是我修改後的項目地址函數

PullToZoomScrollViewcode

下面主要說明下,我在修復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這個問題。

總結

上述的問題,大概通過了兩天的各類嘗試,才獲得結果。並且靈感是在回家以後,不經意的一個瞬間,想到的,因此有時候,遇到問題,本身能夠暫時先放一放,換個時間思惟角度也許就大不同,問題也就迎刃而解。

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

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

相關文章
相關標籤/搜索