Scroller的方法startScroll、fling、computeScrollOffset

最近在使用开源库TableFixHeaders(https://github.com/InQBarna/TableFixHeaders),对于其中Scroller的用法不清楚,故看看这几个方法干了什么。

点与点之间的计算 + 触摸事件的分发。

1. startScroll

当startScroll执行过程中即在duration时间内,computeScrollOffset 方法会一直返回false,但当动画执行完成后会返回返加true.

如果不设置duration,默认DEFAULT_DURATION = 250.

public void startScroll(int startX, int startY, int dx, int dy, int duration) {
    mMode = SCROLL_MODE;
    mFinished = false;
    mDuration = duration;
    mStartTime = AnimationUtils.currentAnimationTimeMillis();
    mStartX = startX;
    mStartY = startY;
    mFinalX = startX + dx;
    mFinalY = startY + dy;
    mDeltaX = dx;
    mDeltaY = dy;
    mDurationReciprocal = 1.0f / (float) mDuration;
}

看代码,这个方法就是把需要滚动的参数传进来。

2.fling

public void fling(int startX, int startY, int velocityX, int velocityY,
        int minX, int maxX, int minY, int maxY) {
    // Continue a scroll or fling in progress
    if (mFlywheel && !mFinished) {
        float oldVel = getCurrVelocity();

        float dx = (float) (mFinalX - mStartX);
        float dy = (float) (mFinalY - mStartY);
        float hyp = (float) Math.hypot(dx, dy);

        float ndx = dx / hyp;
        float ndy = dy / hyp;

        float oldVelocityX = ndx * oldVel;
        float oldVelocityY = ndy * oldVel;
        if (Math.signum(velocityX) == Math.signum(oldVelocityX) &&
                Math.signum(velocityY) == Math.signum(oldVelocityY)) {
            velocityX += oldVelocityX;
            velocityY += oldVelocityY;
        }
    }

    mMode = FLING_MODE;
    mFinished = false;

    float velocity = (float) Math.hypot(velocityX, velocityY);

    mVelocity = velocity;
    mDuration = getSplineFlingDuration(velocity);
    mStartTime = AnimationUtils.currentAnimationTimeMillis();
    mStartX = startX;
    mStartY = startY;

    float coeffX = velocity == 0 ? 1.0f : velocityX / velocity;
    float coeffY = velocity == 0 ? 1.0f : velocityY / velocity;

    double totalDistance = getSplineFlingDistance(velocity);
    mDistance = (int) (totalDistance * Math.signum(velocity));

    mMinX = minX;
    mMaxX = maxX;
    mMinY = minY;
    mMaxY = maxY;

    mFinalX = startX + (int) Math.round(totalDistance * coeffX);
    // Pin to mMinX <= mFinalX <= mMaxX
    mFinalX = Math.min(mFinalX, mMaxX);
    mFinalX = Math.max(mFinalX, mMinX);

    mFinalY = startY + (int) Math.round(totalDistance * coeffY);
    // Pin to mMinY <= mFinalY <= mMaxY
    mFinalY = Math.min(mFinalY, mMaxY);
    mFinalY = Math.max(mFinalY, mMinY);
}

3. computeScrollOffset

功效:返回值为boolean,true说明滚动尚未完成,false说明滚动已经完成。

参考网址:http://www.cnblogs.com/tt_mc/p/3585390.html

public boolean computeScrollOffset() {
    if (mFinished) {
        return false;
    }

    int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);

    if (timePassed < mDuration) {
        switch (mMode) {
        case SCROLL_MODE:
            final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal);
            mCurrX = mStartX + Math.round(x * mDeltaX);
            mCurrY = mStartY + Math.round(x * mDeltaY);
            break;
        case FLING_MODE:
            final float t = (float) timePassed / mDuration;
            final int index = (int) (NB_SAMPLES * t);
            float distanceCoef = 1.f;
            float velocityCoef = 0.f;
            if (index < NB_SAMPLES) {
                final float t_inf = (float) index / NB_SAMPLES;
                final float t_sup = (float) (index + 1) / NB_SAMPLES;
                final float d_inf = SPLINE_POSITION[index];
                final float d_sup = SPLINE_POSITION[index + 1];
                velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);
                distanceCoef = d_inf + (t - t_inf) * velocityCoef;
            }

            mCurrVelocity = velocityCoef * mDistance / mDuration * 1000.0f;

            mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX));
            // Pin to mMinX <= mCurrX <= mMaxX
            mCurrX = Math.min(mCurrX, mMaxX);
            mCurrX = Math.max(mCurrX, mMinX);

            mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY));
            // Pin to mMinY <= mCurrY <= mMaxY
            mCurrY = Math.min(mCurrY, mMaxY);
            mCurrY = Math.max(mCurrY, mMinY);

            if (mCurrX == mFinalX && mCurrY == mFinalY) {
                mFinished = true;
            }

            break;
        }
    }
    else {
        mCurrX = mFinalX;
        mCurrY = mFinalY;
        mFinished = true;
    }
    return true;
}

timePassed表示滚动进行到的时间,若滚动未结束,分SCROLL_MODE和FLING_MODE两种情况计算当前位置。

  • SCROLL_MODE下,
    时间最小单位mDurationReciprocal = 1.0f / (float) mDuration;
    通过差值器mInterpolator确定距离百分比,这里x和y方向使用同一差值器。
    mInterpolator = new ViscousFluidInterpolator(); 是Scroller的静态内部类,取值算法见getInterpolation()所调用的viscousFluid()。

    static class ViscousFluidInterpolator implements Interpolator {
    /* Controls the viscous fluid effect (how much of it). /
    private static final float VISCOUS_FLUID_SCALE = 8.0f;

    private static final float VISCOUS_FLUID_NORMALIZE;
    private static final float VISCOUS_FLUID_OFFSET;
    
    static {
    
        // must be set to 1.0 (used in viscousFluid())
        VISCOUS_FLUID_NORMALIZE = 1.0f / viscousFluid(1.0f);
        // account for very small floating-point error
        VISCOUS_FLUID_OFFSET = 1.0f - VISCOUS_FLUID_NORMALIZE * viscousFluid(1.0f);
    }
    
    private static float viscousFluid(float x) {
        x *= VISCOUS_FLUID_SCALE;
        if (x < 1.0f) {
            x -= (1.0f - (float)Math.exp(-x));
        } else {
            float start = 0.36787944117f;   // 1/e == exp(-1)
            x = 1.0f - (float)Math.exp(1.0f - x);
            x = start + x * (1.0f - start);
        }
        return x;
    }
    
    @Override
    public float getInterpolation(float input) {
        final float interpolated = VISCOUS_FLUID_NORMALIZE * viscousFluid(input);
        if (interpolated > 0) {
            return interpolated + VISCOUS_FLUID_OFFSET;
        }
        return interpolated;
    }
    

    }

  • FLING_MODE下,
    x和y还是同比例变化,这里设定了采样率NB_SAMPLES = 100;(??)
    index和index+1的含义?
    速度因子,velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);
    距离因子,distanceCoef = d_inf + (t - t_inf) * velocityCoef;

4. invalidate() 与 postInvalidate()

5.smoothScrollBy() 与 fling()

6. 其他相关类

参考网址:http://mobile.51cto.com/design-375889.htm
http://www.cnblogs.com/wanqieddy/archive/2012/05/05/2484534.html

VelocityTracker 速度追踪器

追踪用户手指在屏幕上的滑动速度。当你要跟踪一个touch事件的时候,使用obtain()方法得到这个类的实例,然后 用addMovement(MotionEvent)函数将接受到的motionEvent加入到VelocityTracker类实例中。

使用computeCurrentVelocity(int)初始化速率的 单位,并获得当前的事件的速率;然后使用getXVelocity() 或getXVelocity()获得横向和竖向的速率。

ViewConfiguration

定义了android的许多标准的常量(UI的超时、大小和距离等)。

public int getScaledEdgeSlop() 获得一个触摸移动的最小像素值。也就是说,只有超过了这个值,才代表我们该滑屏处理了。

public static int getLongPressTimeout() 获得一个执行长按事件监听(onLongClickListener)的值。也就是说,对某个View按下触摸时,只有超过了这个时间值在,才表示我们该对该View回调长按事件了;否则,小于这个时间点松开手指,只执行onClick监听。

GestureDetector 手势识别器

追踪用户手指在屏幕上的滑动方向

你可能感兴趣的:(Android开发笔记)