ScaleGestureDetector縮放坑點

ScaleGestureDetector縮放坑點


我們知道ScaleGestureDetector可使用getScaleFactor()來獲取縮放因子,但是我們在使用SimpleOnScaleGestureListener的時候會有一些坑點,我們來看下具體的源碼。

public float getScaleFactor() {
        if (inAnchoredScaleMode()) {
            // Drag is moving up; the further away from the gesture
            // start, the smaller the span should be, the closer,
            // the larger the span, and therefore the larger the scale
            final boolean scaleUp =
                    (mEventBeforeOrAboveStartingGestureEvent && (mCurrSpan < mPrevSpan)) ||
                    (!mEventBeforeOrAboveStartingGestureEvent && (mCurrSpan > mPrevSpan));
            final float spanDiff = (Math.abs(1 - (mCurrSpan / mPrevSpan)) * SCALE_FACTOR);
            return mPrevSpan <= 0 ? 1 : scaleUp ? (1 + spanDiff) : (1 - spanDiff);
        }
        return mPrevSpan > 0 ? mCurrSpan / mPrevSpan : 1;
    }

分析源碼可知縮放因子與 mCurrSpan 和 mPrevSpan 有着緊密的聯繫,大部分情況下爲 mCurrSpan / mPrevSpan,mCurrSpan 爲當前兩指觸摸點的距離,
mPrevSpan 爲上一次兩指觸摸點的距離,我們可以通過 getCurrentSpan() 和 getPreviousSpan() 獲取到這兩個參數的值,然後我們來測試這兩個值的變化情況。
在這裏插入圖片描述
可以看到,當我的兩指間距在放大和縮小後,mCurrSpan 會隨着手指間距的變化而變化,但是 mPrevSpan 卻沒有任何變化,所以可能導致我們手指間距變小時,mCurrSpan 依然比 mPrevSpan 大,從而導致內容還是在繼續放大而不是我們希望的縮小。
我們來看下 mPrevSpan 更新的源碼。

final int minSpan = inAnchoredScaleMode() ? mSpanSlop : mMinSpan;
if (!mInProgress && span >=  minSpan &&
        (wasInProgress || Math.abs(span - mInitialSpan) > mSpanSlop)) {
    mPrevSpanX = mCurrSpanX = spanX;
    mPrevSpanY = mCurrSpanY = spanY;
    mPrevSpan = mCurrSpan = span;
    mPrevTime = mCurrTime;
    //這裏onScaleBegin()返回值如果爲false,則mPrevSpan一定會更新
    mInProgress = mListener.onScaleBegin(this); 
}

// Handle motion; focal point and span/scale factor are changing.
if (action == MotionEvent.ACTION_MOVE) {
    mCurrSpanX = spanX;
    mCurrSpanY = spanY;
    mCurrSpan = span;

    boolean updatePrev = true;

    if (mInProgress) {
    	//如果mInProgress爲true, onScale()返回false, 則mPrevSpan不會更新
        updatePrev = mListener.onScale(this);
    }

    if (updatePrev) {
        mPrevSpanX = mCurrSpanX;
        mPrevSpanY = mCurrSpanY;
        mPrevSpan = mCurrSpan;
        mPrevTime = mCurrTime;
    }
}

查看了源碼後我們發現問題,mPrevSpan的更新與否和我們之前綁定的OnScaleGestureListener有直接的關係,也就是我們要確保onScaleBegin()返回true的時候,onScale()也要返回true。
我們再來看一下官方默認實現OnScaleGestureListener接口的SimpleOnScaleGestureListener的源碼。

public static class SimpleOnScaleGestureListener implements OnScaleGestureListener {

    public boolean onScale(ScaleGestureDetector detector) {
        return false;
    }

    public boolean onScaleBegin(ScaleGestureDetector detector) {
        return true;
    }

    public void onScaleEnd(ScaleGestureDetector detector) {
        // Intentionally empty
    }
}

從源碼我們可以知道如果我們使用了SimpleOnScaleGestureListener,那麼mPrevSpan就永不更新,縮放因子就會出現異常。所以我們在使用ScaleGestureDetector的時候如果需要 mPrevSpan 及時更新的話就需要去實現OnScaleGestureListener 不能使用SimpleOnScaleGestureListener。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章