美文网首页
Scroller 均匀滑动

Scroller 均匀滑动

作者: qpan | 来源:发表于2018-05-12 13:14 被阅读15次
    • 用途
      实现有过渡效果的滑动
    • 使用
    Scroller scroller = new Scroller(context);
    
    private void smoothScrollTo(int destX, int destY){
        int scrollX = getScrollX();
        int delta = destX - scrollX;
        scroller.startScroll(scrollX, 0, delta, 0, 1000);
        invalidate();
    }
    
    @Override
    public void computeScroll(){
        if (scroller.computeScrollOffset()){
            scrollTo(scroller.getCurrX(),scroller.getCurrY());
            postInvalidate();
        }
    }
    
    • 解析
    1. 构造函数
       /**
         * Create a Scroller with the specified interpolator. If the interpolator is
         * null, the default (viscous) interpolator will be used. Specify whether or
         * not to support progressive "flywheel" behavior in flinging.
         */
        public Scroller(Context context, Interpolator interpolator, boolean flywheel) {
            mFinished = true;
            if (interpolator == null) {
                mInterpolator = new ViscousFluidInterpolator();
            } else {
                mInterpolator = interpolator;
            }
            mPpi = context.getResources().getDisplayMetrics().density * 160.0f;
            mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction());
            mFlywheel = flywheel;
            mPhysicalCoeff = computeDeceleration(0.84f); // look and feel tuning
        }
    
    1. startScroll: 初始化相关参数
    /**
        * Start scrolling by providing a starting point, the distance to travel,
        * and the duration of the scroll.
        * 
        * @param startX Starting horizontal scroll offset in pixels. Positive
        *        numbers will scroll the content to the left.
        * @param startY Starting vertical scroll offset in pixels. Positive numbers
        *        will scroll the content up.
        * @param dx Horizontal distance to travel. Positive numbers will scroll the
        *        content to the left.
        * @param dy Vertical distance to travel. Positive numbers will scroll the
        *        content up.
        * @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;
       }
    

    设置了一些初始变量

    1. computeScrollOffset 关键方法,计算此时的位置,当结束则返回false,否则返回true
       /**
         * Call this when you want to know the new location.  If it returns true,
         * the animation is not yet finished.
         */ 
        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;
        }
    
    • 重复过程
      invalidate() --->invoke view.draw() ---> invoke computeScroll()
      --->postInvalidate
    • 总结
      Scroller本身并不能实现View的滑动,需要配合View的computeScroll方法才能完成弹性滑动的效果。它不断的让View重绘,而每一次重绘距离滑动起始时间会有一个时间间隔,通过这个时间间隔Scroller就可以得到View当前的滑动位置,从而可以通过scrollTo方法来完成View的滑动。因此,通过每一次重绘导致View进行小幅度的滑动,而多次小幅度滑动就组成了弹性滑动。

    相关文章

      网友评论

          本文标题:Scroller 均匀滑动

          本文链接:https://www.haomeiwen.com/subject/pzecdftx.html