Scroller类的介绍
我们知道想把一个View偏移至指定坐标(x,y)处,利用scrollTo()方法直接调用就OK了,但我们不能忽视的是,该方法本身
来的的副作用:非常迅速的将View/ViewGroup偏移至目标点,而没有对这个偏移过程有任何控制,对用户而言可能是不太
友好的。于是,基于这种偏移控制,Scroller类被设计出来了,该类的主要作用是为偏移过程制定一定的控制流程(后面我们会
知道的更多),从而使偏移更流畅,更完美。
可能上面说的比较悬乎,道理也没有讲透。下面我就根据特定情景帮助大家分析下:
情景: 从上海如何到武汉?
普通的人可能会想,so easy : 飞机、轮船、11路公交车...
文艺的人可能会想, 小 case : 时空忍术(火影的招数)、翻个筋斗(孙大圣的招数)...
不管怎么样,我们想出来的套路可能有两种:
1、有个时间控制过程才能抵达(缓慢的前进) ----- 对应于Scroller的作用
假设做火车,这个过程可能包括: 火车速率,花费周期等;
2、瞬间抵达(超神太快了,都眩晕了,用户体验不太好) ------ 对应于scrollTo()的作用
模拟Scroller类的实现功能:
假设从上海做动车到武汉需要10个小时,行进距离为1000km ,火车速率200/h 。采用第一种时间控制方法到达武汉的
整个配合过程可能如下:
我们每隔一段时间(例如1小时),计算火车应该行进的距离,然后调用scrollTo()方法,行进至该处。10小时过完后,
我们也就达到了目的地了。
相信大家心里应该有个感觉了。我们就分析下源码里去看看Scroller类的相关方法.
其源代码(部分)如下: 路径位于 \frameworks\base\core\java\android\widget\Scroller.java
- public class Scroller {
- private int mStartX; //起始坐标点 , X轴方向
- private int mStartY; //起始坐标点 , Y轴方向
- private int mCurrX; //当前坐标点 X轴, 即调用startScroll函数后,经过一定时间所达到的值
- private int mCurrY; //当前坐标点 Y轴, 即调用startScroll函数后,经过一定时间所达到的值
- private float mDeltaX; //应该继续滑动的距离, X轴方向
- private float mDeltaY; //应该继续滑动的距离, Y轴方向
- private boolean mFinished; //是否已经完成本次滑动操作, 如果完成则为 true
- //构造函数
- public Scroller(Context context) {
- this(context, null);
- }
- public final boolean isFinished() {
- return mFinished;
- }
- //强制结束本次滑屏操作
- public final void forceFinished(boolean finished) {
- mFinished = finished;
- }
- public final int getCurrX() {
- return mCurrX;
- }
- /* Call this when you want to know the new location. If it returns true,
- * the animation is not yet finished. loc will be altered to provide the
- * new location. */
- //根据当前已经消逝的时间计算当前的坐标点,保存在mCurrX和mCurrY值中
- public boolean computeScrollOffset() {
- if (mFinished) { //已经完成了本次动画控制,直接返回为false
- return false;
- }
- int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
- if (timePassed < mDuration) {
- switch (mMode) {
- case SCROLL_MODE:
- float x = (float)timePassed * mDurationReciprocal;
- ...
- mCurrX = mStartX + Math.round(x * mDeltaX);
- mCurrY = mStartY + Math.round(x * mDeltaY);
- break;
- ...
- }
- else {
- mCurrX = mFinalX;
- mCurrY = mFinalY;
- mFinished = true;
- }
- return true;
- }
- //开始一个动画控制,由(startX , startY)在duration时间内前进(dx,dy)个单位,即到达坐标为(startX+dx , startY+dy)出
- public void startScroll(int startX, int startY, int dx, int dy, int duration) {
- mFinished = false;
- mDuration = duration;
- mStartTime = AnimationUtils.currentAnimationTimeMillis();
- mStartX = startX; mStartY = startY;
- mFinalX = startX + dx; mFinalY = startY + dy;
- mDeltaX = dx; mDeltaY = dy;
- ...
- }
- }
其中比较重要的两个方法为:
public void startScroll(int startX, int startY, int dx, int dy, int duration)
函数功能说明:根据当前已经消逝的时间计算当前的坐标点,保存在mCurrX和mCurrY值中
public void startScroll(int startX, int startY, int dx, int dy, int duration)
函数功能说明:开始一个动画控制,由(startX , startY)在duration时间内前进(dx,dy)个单位,到达坐标为
(startX+dx , startY+dy)处。
PS : 强烈建议大家看看该类的源码,便于后续理解。
知识点二: computeScroll()方法介绍
为了易于控制滑屏控制,Android框架提供了 computeScroll()方法去控制这个流程。在绘制View时,会在draw()过程调用该
方法。因此, 再配合使用Scroller实例,我们就可以获得当前应该的偏移坐标,手动使View/ViewGroup偏移至该处。
computeScroll()方法原型如下,该方法位于ViewGroup.java类中
- /**
- * Called by a parent to request that a child update its values for mScrollX
- * and mScrollY if necessary. This will typically be done if the child is
- * animating a scroll using a {@link android.widget.Scroller Scroller}
- * object.
- */由父视图调用用来请求子视图根据偏移值 mScrollX,mScrollY重新绘制
- public void computeScroll() { //空方法 ,自定义ViewGroup必须实现方法体
- }