Scroller类的源码分析以及使用
Scroller类是用于处理滚动效果的一个类,我们平时使用的ViewPager,可以触摸左右滑动页面,其内部就是使用了Scroller。由于Scroller类是配合View或者ViewGroup的子类来使用的,所以,在了解Scroller类之前,我们先了解一下View的scrollTo方法和ScrollBy方法,下面我们来看看这两个方法的源码:
从源码中可以看出,scrollBy方法其实最终也是调用scrollTo方法,对于View如果调用这两个方法,其实就是移动View中的内容,注意是移动View中的内容,而不是View自身的位置。如果是ViewGroup调用这两个方法,则是移动ViewGroup中的子View的位置。
scrollTo(int x,int y)方法是,将内容移动到(x,y)这个坐标点处,scrollBy方法将View中的内容相当于当前位置,在x方向移动x距离,在y距离移动y段距离。
讲解完View的scrollTo方法和scrollBy方法后,我们再来看看Scroller类,首先看看Scroller类的构造方法:
可以看到无论使用哪一个构造方法都会调用第三个构造方法,如果没有指定插值器,系统会为我们创建一个ViscousFluidInterpolator类型的interpolator,flywheel参数也是根据版本号来决定的。
一般我们在项目中,使用Scroller的startScroll方法,配合View的invalidate方法,并重写View的computeScroll方法:
最后效果如图:可以通过这个链接查看。
https://s31.aconvert.com/convert/p3r68-cdx67/rd7mb-3aql1.gif
我们先从smoothScrollTo开始分析,它会调用scroller.startScroll方法
startScroll方法其实并未做任何的滚动的操作,只是将传入的参数进行了赋值保存,所以我们在自定义的com.example.myapplication.ScrollView中只是调用startScroll方法时,并不能起到滚动的效果,还需要使用View的invalidate方法,这时候View的draw方法再次被调用,同时在draw方法中又会调用computeScroll方法
这样,我们重写的computeScroll方法就会执行。
接着调用scrollTo方法进行滚动,然后继续invalidate继续重绘。继续调用computeScroll,继续滚动,接着重绘。通过一连串的这个递归调用,每次滚动一点点距离,整个过程衔接起来就完成了平滑的滚动的效果。那么什么时候退出这个循环呢?
当mScroller的computeScrollOffset方法返回值为false。
可以看到,当返回值为true时候,那么它就会一直这样不停的递归,最终完成移动到指定位置的滚动效果,在mFinished时,也就是还未滚动到指定位置时,会先计算一个timePassed,如果这个时间小于指定的滚动时间
而且我们没设置mMode这个属性的话,默认是SCROLL_MODE,当我们调用startScroll方法默认设置的。
所以当未达到滚动时间会执行SCROLL_MODE这个case,在这个case中,会根据timePassed,计算出最新的mCurrentX,mCurrentY,这样我们可以在computeScroll方法中,通过mScroller.getCurrentX();获取到的是最新的mCurrentX。这样再调用scrollTo方法,才会将View的内容滚动到最新的位置。
总结:Scroller原理就是:调用startScroll方法,先告诉系统要移动的起始点和要移动的距离,还有完成的移动的时间,并且配合View的computerScroll方法,通过调用View的invalidate方法进行重绘,这样computeScroll方法就会执行,根据流失的时间和插值器来计算最新需要移动的位置,然后再通过scrollTo来移动到这个最新的位置,最后通过递归来完成整个过程以实现滚动的效果。