Android的Scroller源代码分析

首先先来实现一个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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值