Scroller 的滑动应用详解

最近研究了一下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();//此处需要手动调用刷新,否则不会看到移动效果
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值