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。

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