scroller的一些用法
view中有两个方法 public void scrollTo(int x, int y)和 public void scrollBy(int x, int y) 通俗来说,scrollTo是到坐标为x和y的位置,scrollBy是继续偏移x和y个单位的坐标。 看源代码
public void scrollBy(int x, int y) {
scrollTo(mScrollX + x, mScrollY + y);
}
发现scrollBy是调用了scrollTo方法,在原先参数的基础上添加了原始坐标位置,相加后传递给了scrollTo方法。再看看scrollTo方法的源码
public void scrollTo(int x, int y) {
// 偏移位置发生了改变 mScrollX 和mScrollY 是view现在所在的位置
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x; //赋新值,保存当前便宜量
mScrollY = y;
//回调onScrollChanged方法 自己可以实现该接口
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (!awakenScrollBars()) {
invalidate(); //一般都会引起重绘
}
}
}
在scrollTo方法里面,如果控件内容顶着左上角,x值为正值,则整个控件里面的内容向左移动,y值为正值,则控件里面的内容向上移动;x和y为负值,则移动方向相反。简单的看成x轴向左为正,y轴向上为正的坐标轴即可。以控件左上定点为(0,0)坐标轴。
如果想获取view的偏移量,可以调用view向外边暴露的方法,getScrollX()方法和getScrollY()方法即可。
如果我们想在界面上移动view,比如说在scrollView中移动子控件,理论上来说上面两个方法够用,但有个弊端是移动速度太快,几乎是瞬移,用户还没看到控件的滑动效果,结果控件一瞬间就到目的地了,体验不好,基于此,google推出了Scroller辅助类,把view的位移速度给降了下来,并且可以人为控制。
Scroller 有n组成员变量,都是相对应的,
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;
}
// 根据当前已经消逝的时间计算当前的坐标点,保存在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;
...
}
}
在自定义view时,要new一个Scroller,并且重写
public void computeScroll() {
}
方法,在里面写一些固定的判断。
比如在view里面对外暴露一个函数
public void startMove(){
//使用动画控制偏移过程 , 2s内到位
mScroller.startScroll(2 * getWidth(), 0, getWidth(), 0,2000);
//其实点击按钮的时候,系统会自动重新绘制View,我们还是手动加上吧。
invalidate();
}
public void computeScroll() {
Log.e(TAG, "移动了");
// 如果返回true,表示动画还没有结束,只有在startScroll完成时 才会为false
if (mScroller.computeScrollOffset()) {
Log.e(TAG, mScroller.getCurrX() + "======" + mScroller.getCurrY());
// 产生了动画效果,根据当前值 每次滚动一点
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
//此时同样也需要刷新View ,否则效果可能有误差
postInvalidate();
}
else
Log.i(TAG, "移动完成了");
}
上面就这么简单,view就移动了。但是有一点需要分辨,就是
mScroller.startScroll(getWidth(), 0, 2*getWidth(), 0,2000); 这个方法,也就是scroller中的
public void startScroll(int startX, int startY, int dx, int dy, int duration)
中的参数的值,如果dx为正数,view向左滑动,dy为正值,view向上滑动,
scroller体系构建的左边体系是x轴向左为正方向,y轴向上为正方向,原点坐标轴为屏幕左上角。所以参数方面和上述的scrollBy(int x, int y)方法,如果参数相同的话,会发现view的移动方向是相反的,这点一定要分辨清楚,不要弄混了。实际上可以理解为是view里面的内容在移动,而非view在动。
手指触摸滑动也有个辅助类 VelocityTracker类
public void computeCurrentVelocity (int units)
//功能:以每像素units单位考核移动速率,赋予值1000或600都行
public float getXVelocity ()
//x轴移动速率
一般是在view的onTouchEvent(MotionEvent event)方法里调用,先new一个对象,然后把触发事件给添加进去
//获得VelocityTracker对象,并且添加滑动对象
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event);
关键起作用的是在MotionEvent.ACTION_UP里面,屏幕在滑动,手指头突然离开屏幕,这时候控件一般还要在缓冲滑动一会,就像快速滑动listview时,手指突然离开屏幕,listview还要滑动一会慢慢停止,这样体验比较好,手指抬起后,就是MotionEvent.ACTION_UP里面的逻辑了
设置参数,拿到移动的速率
velocityTracker.computeCurrentVelocity(1000);
//计算速率
int velocityX = (int) velocityTracker.getXVelocity() ;
然后做逻辑判断,看 velocityX 的绝对值是否比自定义的要大,如果大,可以做一些页面的滑动操作,比如调用 mScroller.startScroll(getScrollX(), 0, dx, 0,Math.abs(dx) * 2); 方法,页面会慢慢减低滑动速率,最终到指定的位置。
view中有两个方法 public void scrollTo(int x, int y)和 public void scrollBy(int x, int y) 通俗来说,scrollTo是到坐标为x和y的位置,scrollBy是继续偏移x和y个单位的坐标。 看源代码
public void scrollBy(int x, int y) {
scrollTo(mScrollX + x, mScrollY + y);
}
发现scrollBy是调用了scrollTo方法,在原先参数的基础上添加了原始坐标位置,相加后传递给了scrollTo方法。再看看scrollTo方法的源码
public void scrollTo(int x, int y) {
// 偏移位置发生了改变 mScrollX 和mScrollY 是view现在所在的位置
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x; //赋新值,保存当前便宜量
mScrollY = y;
//回调onScrollChanged方法 自己可以实现该接口
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (!awakenScrollBars()) {
invalidate(); //一般都会引起重绘
}
}
}
在scrollTo方法里面,如果控件内容顶着左上角,x值为正值,则整个控件里面的内容向左移动,y值为正值,则控件里面的内容向上移动;x和y为负值,则移动方向相反。简单的看成x轴向左为正,y轴向上为正的坐标轴即可。以控件左上定点为(0,0)坐标轴。
如果想获取view的偏移量,可以调用view向外边暴露的方法,getScrollX()方法和getScrollY()方法即可。
如果我们想在界面上移动view,比如说在scrollView中移动子控件,理论上来说上面两个方法够用,但有个弊端是移动速度太快,几乎是瞬移,用户还没看到控件的滑动效果,结果控件一瞬间就到目的地了,体验不好,基于此,google推出了Scroller辅助类,把view的位移速度给降了下来,并且可以人为控制。
Scroller 有n组成员变量,都是相对应的,
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;
}
// 根据当前已经消逝的时间计算当前的坐标点,保存在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;
...
}
}
在自定义view时,要new一个Scroller,并且重写
public void computeScroll() {
}
方法,在里面写一些固定的判断。
比如在view里面对外暴露一个函数
public void startMove(){
//使用动画控制偏移过程 , 2s内到位
mScroller.startScroll(2 * getWidth(), 0, getWidth(), 0,2000);
//其实点击按钮的时候,系统会自动重新绘制View,我们还是手动加上吧。
invalidate();
}
public void computeScroll() {
Log.e(TAG, "移动了");
// 如果返回true,表示动画还没有结束,只有在startScroll完成时 才会为false
if (mScroller.computeScrollOffset()) {
Log.e(TAG, mScroller.getCurrX() + "======" + mScroller.getCurrY());
// 产生了动画效果,根据当前值 每次滚动一点
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
//此时同样也需要刷新View ,否则效果可能有误差
postInvalidate();
}
else
Log.i(TAG, "移动完成了");
}
上面就这么简单,view就移动了。但是有一点需要分辨,就是
mScroller.startScroll(getWidth(), 0, 2*getWidth(), 0,2000); 这个方法,也就是scroller中的
public void startScroll(int startX, int startY, int dx, int dy, int duration)
中的参数的值,如果dx为正数,view向左滑动,dy为正值,view向上滑动,
scroller体系构建的左边体系是x轴向左为正方向,y轴向上为正方向,原点坐标轴为屏幕左上角。所以参数方面和上述的scrollBy(int x, int y)方法,如果参数相同的话,会发现view的移动方向是相反的,这点一定要分辨清楚,不要弄混了。实际上可以理解为是view里面的内容在移动,而非view在动。
手指触摸滑动也有个辅助类 VelocityTracker类
public void computeCurrentVelocity (int units)
//功能:以每像素units单位考核移动速率,赋予值1000或600都行
public float getXVelocity ()
//x轴移动速率
一般是在view的onTouchEvent(MotionEvent event)方法里调用,先new一个对象,然后把触发事件给添加进去
//获得VelocityTracker对象,并且添加滑动对象
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event);
关键起作用的是在MotionEvent.ACTION_UP里面,屏幕在滑动,手指头突然离开屏幕,这时候控件一般还要在缓冲滑动一会,就像快速滑动listview时,手指突然离开屏幕,listview还要滑动一会慢慢停止,这样体验比较好,手指抬起后,就是MotionEvent.ACTION_UP里面的逻辑了
设置参数,拿到移动的速率
velocityTracker.computeCurrentVelocity(1000);
//计算速率
int velocityX = (int) velocityTracker.getXVelocity() ;
然后做逻辑判断,看 velocityX 的绝对值是否比自定义的要大,如果大,可以做一些页面的滑动操作,比如调用 mScroller.startScroll(getScrollX(), 0, dx, 0,Math.abs(dx) * 2); 方法,页面会慢慢减低滑动速率,最终到指定的位置。