美文网首页
Android的Scroller源代码分析

Android的Scroller源代码分析

作者: minminaya | 来源:发表于2017-08-17 20:55 被阅读688次

    首先先来实现一个Scroller滑动

    1.新建一个View,给它画上一个红色的矩形,左定点坐标是(100,100),并且在构造函数中初始化Scroller

    public class MyView extends View {
    
        private Scroller scroller;
    
        private Paint paint = new Paint();
    
        public MyView(Context context) {
            super(context);
            scroller = new Scroller(context);
        }
    
        public MyView(Context context, AttributeSet attrs) {
            super(context, attrs);
            scroller = new Scroller(context);
        }
    
        public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            scroller = new Scroller(context);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            paint.setColor(Color.RED);
            canvas.drawRect(100, 100, 300, 300, paint);
        }
    

    2.重写view的computeScroll()方法,系统绘制view的时候会在draw()方法调用computeScroll()。

    @Override
        public void computeScroll() {
            super.computeScroll();
            if (scroller.computeScrollOffset()) {
               //通过Scroller来获取当前的滚动值
                scrollTo(scroller.getCurrX(), scroller.getCurrY());
    //重绘,会重新调用computeScroll() 不断移动view
                invalidate();
            }
        }
    

    3.写一个方法开始移动view,里面调用startScroll()方法

    public void smoothScrollTo(int destX,  int destY) {
            int scrollX = getScrollX();
            int deltaX = destX - scrollX;
            scroller.startScroll(scrollX, 0, -deltaX, 0, 10000);
            invalidate();
        }
    

    4.在布局文件中引用,Activity加载,写一个按钮控制smoothScrollTo()方法

        public void startScroller(View view) {
            myView.smoothScrollTo(400, 100);
        }
    

    5.点击按钮后,效果图

    2.gif

    分析源代码

    1.构造函数,有三个构造方法,不过第一种用的最广,第二种,传入一个插值器,然后在第三种中判断了一下插值器是否为空,不为空则使用默认的ViscousFluidInterpolator插值器

    
        public Scroller(Context context) {
            this(context, null);
        }
    
       
        public Scroller(Context context, Interpolator interpolator) {
            this(context, interpolator,
                    context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB);
        }
    
        
        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
        }
    

    2.主要方法

    • startScroll(),有4个参数的和5个参数的,4个参数本质上也是调用了5个参数的startScroll(),区别在4个参数的用了默认的duration。
      startX:开始滑动的起点x
      startY:开始滑动的起点y
      dx:滑动的距离x,使用时注意正负
      dy:滑动的距离y,使用时注意正负
    
    public void startScroll(int startX, int startY, int dx, int dy) {
            startScroll(startX, startY, dx, dy, DEFAULT_DURATION);
        }
    
    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;
        }
    

    startScroll()方法是用来保存传进来的各种参数的,没有用来具体开启滑动的逻辑,而我们要使View滑动,startScroll()要用到invalidate()来使view进行重绘,从而调用draw()方法,这样draw()方法里的就会call到View中的computeScroll()方法。View中的computeScroll()方法是空实现,我们需要重写它

    3.重写computeScroll()方法

    @Override
        public void computeScroll() {
            super.computeScroll();
            if (scroller.computeScrollOffset()) {
                //滚动的逻辑
                scrollTo(scroller.getCurrX(), scroller.getCurrY());
              //接着重绘
                invalidate();
            }
        }
    

    可以看到computeScroll()里用到了scrollTo()以滚动View,接着调用invalidate()会重新call到View中的draw()方法,从而不断的调用computeScroll()方法,使view一点一点的滑动,从而实现了平滑滚动。

    4.其中if判断框中的computeScrollOffset()是用来获取当前位置的ScrollX和ScrollY的,如果返回true这说明滑动未结束

    public boolean computeScrollOffset() {
            if (mFinished) {
                return false;
            }
            //动画持续时间
            int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
            //如果当前的动画持续时间小于设置的滑动持续时间(其实就是当前view滚动还没完的意思)
            if (timePassed < mDuration) {
                switch (mMode) {
                case SCROLL_MODE:
                    //通过插值器计算该时间段移动的距离mCurrX ,mCurrX 
                    final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal);
                    mCurrX = mStartX + Math.round(x * mDeltaX);
                    mCurrY = mStartY + Math.round(x * mDeltaY);
                    break;
                case FLING_MODE:
                    ...//省略
            }
            else {
                mCurrX = mFinalX;
                mCurrY = mFinalY;
                mFinished = true;
            }
            return true;
        }
    

    5.总结整个过程就是

    Scroller过程

    end

    相关文章

      网友评论

          本文标题:Android的Scroller源代码分析

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