在android开发中,系统提供的控件中有实现View或ViewGroup位置移动的功能,表象上来看无非就2种情况:
(1)View在父ViewGroup中相对父ViewGroup的位置变化;
(2)View内部内容相对自己边界的位置变化;
其中(1)的原理就是设置View的left,top,right,bottom变量来实现位置移动;
(2)的原理就要用到scroller了,View内部变量有mScrollerX和mScrollerY,这2个变量就是控制View内部内容滚动的。以下介绍Scroller的原理:
从Scroller源码可以看出这是一个工具类,主要就是计算与位置相关的数据;
private final Interpolator mInterpolator;
private int mMode; //有2种模式:Scroll_mode=0,Fling_mode=1
private int mStartX; //x坐标起始位置
private int mStartY; //y坐标起始位置
private int mFinalX; //x坐标终止位置
private int mFinalY; //y坐标终止位置
private int mMinX;
private int mMaxX;
private int mMinY;
private int mMaxY;
private int mCurrX; //x坐标当前位置
private int mCurrY; //y坐标当前位置
private long mStartTime; //开始动作时的时间
private int mDuration;
private float mDurationReciprocal;
private float mDeltaX;
private float mDeltaY;
private boolean mFinished;
private boolean mFlywheel;
private float mVelocity;
private float mCurrVelocity;
private int mDistance;
/************************************************/
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;
}
View源码中有一个方法
public void computeScroll() {
}
这个方法要在子类中去实现,就是调用Scroller的相关方法去实现滚动效果;View类内部定义有mScrollerx和mScrollerY变量,这2个变量的赋值操作就在startScroll(int startX, int startY, int dx, int dy, int duration) 中;
fling快速滑动的实现和startScroll方法一样,都是设置Scroller中的相关变量。
Scroller中记录的各种变量其实有用的就是mScrollerx和mScrollery,只有在调用View的
public void scrollTo(int x, int y) {
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x;
mScrollY = y;
invalidateParentCaches();
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (!awakenScrollBars()) {
postInvalidateOnAnimation();
}
}
}的时候才从Scroller类中取出mScrollerX和mScrollerY变量赋值到View的mScrollerX和mScrollerY中,然后通过调用View的invalidate()方法使View重绘操作。
在computeScroll()方法的实现中一般是这样的:
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
invalidate();
}
mScroller.computeScrollOffset()是判断有没有滚动到当前位置,返回true表示还没有到当前位置,返回false就表示已经滚动结束。