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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,176评论 5 469
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,190评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,232评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,953评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,879评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,177评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,626评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,295评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,436评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,365评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,414评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,096评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,685评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,771评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,987评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,438评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,032评论 2 341

推荐阅读更多精彩内容