Scroller 的滑动应用详解

来源:互联网 发布:有利网 骗局知乎 编辑:程序博客网 时间:2024/05/21 05:17

最近研究了一下qq中listview 滑动出现删除按钮的操作,找到了一个SwipeMenuListView的类库,于是认真的研读了一下代码,确实有很多可学习的知识,其中有一个地方用到了ScrollerCompat这个类,之前确实没有接触过,所以认知学习了一下,这个类,主要是用来支持自动滑动的,其中用到了几个重要的方法:
1、public void startScroll (int startX, int startY, int dx, int dy, int duration)
这个方法其实网上有一堆的详细介绍,但是我发现对几个参数的介绍分歧很大,当时我看的时候确实很困惑,所以仔细研究了一下源码,确定了正确的答案,下面分享给大家,先看一下源码:

/**     * Start scrolling by providing a starting point and the distance to travel.     * 翻译:通过设置一个起始点和移动距离来启动一个滚动     * @param startX Starting horizontal scroll offset in pixels. Positive     *        numbers will scroll the content to the left.     *翻译:startX代表水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动,也就是x轴起始位置     * @param startY Starting vertical scroll offset in pixels. Positive numbers     *        will scroll the content up.     * 翻译:startY代表垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动     * @param dx Horizontal distance to travel. Positive numbers will scroll the     *        content to the left.     * 翻译:dx 代表水平方向的滑动距离,正值表明向左滑动     * @param dy Vertical distance to travel. Positive numbers will scroll the     *        content up.     * 翻译:dy 代表垂直方向的滑动距离,正值表明向上滑动     * @param duration Duration of the scroll in milliseconds.     * 翻译:整个滑动过程所经历的滑动时间,单位毫秒     */    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;    }

首先,这个方法我需要强调一下,网上有些人说dx,dy代表终点位置,我想现在我把源代码展示出来了,大家看一下mFinalX = startX + dx;也应该能够看明白是一个偏移量,也就是移动距离。需要提醒一下 ,我发现SwipeMenuListView的作者也理解错了,将dx理解成终点了,大家用的时候可以注意一下,但是不影响使用。
另外,此处值得正负和轴的方向正好相反,也就是说,如果想向右滑动,则需要设定为
startScroll(负数, 0, 负数, 0, int duration);startX和dx(或startY和dy)正负号一定要统一。
最后 duration代表的是整个移动过程的总时间,默认250ms,不是每一帧移动的时间间隔,网上有的朋友解释的不正确。

2、 public boolean computeScrollOffset()这个方法要明确一点是,是用来判断整个滚动过程是否完全走完,如果走完的返回false,否则返回true,网上有的解释正好相反,大家看一下下面的源代码应该会一目了然。

 /**     * Call this when you want to know the new location.  If it returns true,     * the animation is not yet finished.  loc will be altered to provide the     * new location.     */     public boolean computeScrollOffset() {        if (mFinished) {            return false;        }        int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);        if (timePassed < mDuration) {            switch (mMode) {            case SCROLL_MODE:                float x = timePassed * mDurationReciprocal;                if (mInterpolator == null)                    x = viscousFluid(x);                 else                    x = mInterpolator.getInterpolation(x);                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;    }

3、public void scrollTo(int x, int y)让试图滚动到指定位置

/**     * Set the scrolled position of your view. This will cause a call to     * {@link #onScrollChanged(int, int, int, int)} and the view will be     * invalidated.     * @param x the x position to scroll to     * 滚动到的X位置     * @param y the y position to scroll to     * 滚动到的Y位置     */    public void scrollTo(int x, int y) {        if (mScrollX != x || mScrollY != y) {            int oldX = mScrollX;            int oldY = mScrollY;            mScrollX = x;            mScrollY = y;            invalidateParentCaches();            onScrollChanged(mScrollX, mScrollY, oldX, oldY);            if (!awakenScrollBars()) {                postInvalidateOnAnimation();            }        }    }

4、public void computeScroll() 这个方法没有源码,是一个空方法,需要自己来重写。在试图重绘的时候回调用这个方法,就是onDraw()里面调用。

下面给大家简单介绍一下应用:
分一下三步:
第一步:创建ScrollerCompat对象

mScroller= ScrollerCompat.create(getContext(),mInterpolator);//mInterpolator可以省略就是动画效果

第二步:重写computeScroll()

computeScroll(){ if (mScroller.computeScrollOffset()) { //此处一定要进行判断,否则后面调用 postInvalidate();会陷入死循环,无限刷新,导致死机                        // 产生了动画效果,根据当前值 每次滚动一点              scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); //让试图移动到指定位置                       postInvalidate();  //不可省略,让onDraw继续调用本方法,类似递归        }  }

第三步:手动启动滚动

 startScroll  (0, 0, 200, 0, 350); postInvalidate();//此处需要手动调用刷新,否则不会看到移动效果
0 0
原创粉丝点击