因为书写自定义控件,需要用到view滑动,请教同事,用到了OverScroller类,但是不甚了解,在这里记录一下其常用的api.
OverScroller和Scroller有什么区别呢?事实上,这两个类都属于Scrollers,Scroller出现的比较早,在API1就有了,OverScroller是在API9才添加上的,出现的比较晚,所以功能比较完善,Over的意思就是超出,即OverScroller提供了对超出滑动边界的情况的处理,这两个类80%的API是一致的,OverScroller比Scroller添加了几个方法。
但是!Scrollers并不是控制View进行滚动,包括内容或者是位置,实际上,Scrollers只是一个控件移动轨迹的辅助计算类,如果你想滚,他能帮你计算什么时间应该滚到什么位置,但是滚不滚,全靠你自觉~所以说,滚动位置由Scrollers计算出来了,我们在什么时候滚呢?滚多少呢?这时候,就要View的一个回调函数computeScroll()出马了。
先撇开Scroller类不谈,其实任何一个控件都是可以滚动的,因为在View类当中有scrollTo()和scrollBy()这两个方法,
这两个方法都是用于对View进行滚动的,那么它们之间有什么区别呢?简单点讲,scrollBy()方法是让View相对于当前的位置滚动某段距离,而scrollTo()方法则是让View相对于初始的位置滚动某段距离。不管是scrollTo()还是scrollBy()方法,滚动的都是该View内部的内容。
另外还有一点需要注意,就是两个scroll方法中传入的参数,第一个参数x表示相对于当前位置横向移动的距离,正值向左移动,负值向右移动,单位是像素。第二个参数y表示相对于当前位置纵向移动的距离,正值向上移动,负值向下移动,单位是像素。
但是scrollTo()和scrollBy()这两个方法完成的滚动效果是跳跃式的,没有任何平滑滚动的效果。没错,只靠scrollTo()和scrollBy()这两个方法是很难完成ViewPager这样的效果的,因此我们还需要借助另外一个关键性的工具,也就我们今天的主角Scroller。
Scroller的基本用法其实还是比较简单的,主要可以分为以下几个步骤:
1. 创建Scroller的实例
2. 调用startScroll()方法来初始化滚动数据并刷新界面
3. 重写computeScroll()方法,并在其内部完成平滑滚动的逻辑
下面简单介绍一下常用的API:
getCurrX() :获取mScroller当前水平滚动的位置
getCurrY() : 获取mScroller当前竖直滚动的位置
getFinalX() : 获取mScroller最终停止的水平位置
getFinalY() : 获取mScroller最终停止的竖直位置
mScroller.setFinalX(int newX) //设置mScroller最终停留的水平位置,没有动画效果,直接跳到目标位置
mScroller.setFinalY(int newY) //设置mScroller最终停留的竖直位置,没有动画效果,直接跳到目标位置
开始滚动动画:
startScroll(int startX, int startY, int dx, int dy)
startScroll(int startX, int startY, int dx, int dy, int duration)
参数:
startX:滚动的x方向起始点
startY:滚动的y方向起始点
dx:x方向的偏移量
dy:y方向的偏移量
duration:滚动所消耗的时间,默认为250毫秒
mScroller.computeScrollOffset() //返回值为boolean,true说明滚动尚未完成,false说明滚动已经完成。
这是一个很重要的方法,通常放在View.computeScroll()中,用来判断是否滚动是否结束。
isFinished() 用来判断当前滚动是否结束
OverScroller比Scroller添加了以下几个方法:
isOverScrolled()
返回当前的位置是否有效 或者是否超出滚动边界。
springBack(int startX, int startY, int minX, int maxX, int minY, int maxY)
springBack英文意思就是回弹吧,没错,这个方法就是实现回弹效果,或者说让视图回复原来位置。
/*参数,前两个是开始位置,是绝对坐标,minX和maxX是用来设定滚动范围的,
也是绝对坐标范围,如果startX不在这个范围里面,
比如大于maxX,就会触发computeScroll(),我们可以移动距离,
最终回弹到maxX所在的位置,并返回true,从而完成后续的滚动效果,比minX小的话,
就会回弹到minX,一样的道理。所以我们可以像上面代码里面一样,判断是否在范围内,在的话,
就invalidate()一下,触发滚动动画*/
notifyHorizontalEdgeReached(int startX, int finalX, int overX)
通知水平滚动是否到达边界,通常这个信息来处理 知道什么时候已经开始滚动,比如在调用fling这个方法,然而很多情况下,这不能提前知道 ,这个方法将 开始X到结束X 转化成合适的值 作为当前的动作和动画。
notifyVerticalEdgeReached(int startY, int finalY, int overY)
通知垂直滚动是否到达边界,通常 这个信息来处理 知道什么时候已经开始滚动,比如在调用fling这个方法,然而很多情况下,这不能提前知道 ,这个方法将 开始X到结束X 转化成合适的值 作为当前的动作和动画。
fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY, int overX, int overY)
fling方法Scroller类也有,但OverScroller多出两个参数:overX、overY
[overX] x轴超出回弹距离
[overY] y轴超出回弹距离
首先,我们两分析一下public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY)方法
[startX] :x轴起始位置
[startY] :y轴起始位置
[velocityX] :x轴滑动速度
[velocityY] :y轴滑动速度
[minX] :x轴最小边界
[maxX] :x轴最大边界
[minY] :y轴最小边界
[maxY] :y轴最大边界
看到以上参数的解释,我想应该就很好理解了。
假设,最小边界为10,最大边界为50。
那么如果起始滑动速度为5,那么滑动距离不为5,而是10;
如果起始滑动速度为20,那么滑动距离为20;
如果起始滑动速度为60,那么滑动距离不为60,而是50;
OverScroller新增的方法中多了两个参数:overX、overY。
假设超出回弹距离为20,那么
那么如果起始滑动速度为5,那么滑动距离不为5,而是10,无回弹效果;
如果起始滑动速度为20,那么滑动距离为20,无回弹效果;
如果起始滑动速度为60,那么滑动距离为60,并回弹到50位置;
如果起始滑动速度为80,那么滑动距离为70,并回弹到50位置;
插值器:
默认情况下Scroller
使用的插值器是ViscousFluidInterpolator
,从字面意义上看是一个粘性流体插值器。
//默认插值器是ViscousFluidInterpolator
Scroller mScroller = new Scroller(mContext);
//指定一个插值器
Scroller mScroller = new Scroller(mContext, new AccelerateDecelerateInterpolator());
//指定一个插值器,第三个参数表示是否开启“飞轮”效果,也就是多次滚动时速度叠加
Scroller mScroller = new Scroller(mContext, new AccelerateDecelerateInterpolator(), false);
Scroller其实就是在scrollTo(x, y)
和scrollBy(x, y)
的基础上添加滚动效果,滚动效果是一个动画,当我们new
一个Scroller对象时,就已经指定了一个插值器,下面来说明一下各种插值器:
ViscousFluidInterpolator
这是一个默认插值器,当构造Scroller
时,如果不传递插值器或者插值器为null时,系统默认使用ViscousFluidInterpolator
插值器。
AccelerateDecelerateInterpolator
在动画开始与结束的时候速率改变比较慢,在中间的时候速率较快。
AccelerateInterpolator
在动画开始的地方速率改变比较慢,然后开始加速。
AnticipateInterpolator
开始的时候向后然后向前甩。
如图所示
48.gif
AnticipateOvershootInterpolator
开始的时候向后然后向前甩一定值后返回最后的值。
如图所示:
49.gif
BounceInterpolator
反弹插值器。
如图所示:
50.gif
CycleInterpolator
动画循环播放特定的次数,速率改变沿着正弦曲线。
51.gif
DecelerateInterpolator
在动画开始的地方快然后慢。
52.gif
LinearInterpolator
以常量速率改变。
52.gif
OvershootInterpolator
向前甩一定值后再回到原来位置.
PathInterpolator
路径插值器,我们可以按照自己想要的轨迹滚动。
PathInterpolator(Path path)
PathInterpolator(float controlX, float controlY)
PathInterpolator(float controlX1, float controlY1, float controlX2, float controlY2)
如果学习Path使用的话,这篇博客是个不错的选择Android开发之Path详解
FastOutLinearInInterpolator
MaterialDesign基于贝塞尔曲线的插补器效果:依次慢慢快。
FastOutSlowInInterpolator
基于贝塞尔曲线的插补器效果:依次慢快慢
LinearOutSlowInInterpolator
基于贝塞尔曲线的插补器效果:依次快慢慢
以上的插值器运用比较广泛,在Scroller
中设置一个插值器可以优化滚动的效果。
参考:https://www.jianshu.com/p/ee3f8d7d10a3
https://blog.csdn.net/Iamzgx/article/details/49227137
https://blog.csdn.net/lib739449500/article/details/51850276