Android提供了滚动帮助类Scroller,手势帮助类GestureDetector和速度帮助类VelocityTracker,之所以叫帮助类,是因为它们和正常的UI显示没有直接的关系,它们只是提供一些算法帮助,帮助我们得到想要的坐标值或者事件监听。下面分别讲一下这三个帮助类。
Scroller:
Scoller是自动滚动的帮助类,用到的场合是让某个控件自动滚动。比如有这么一个需求,我想让一个按钮5秒之内从(100,120)这个坐标滚动到(200,300)这个坐标。我们可以自己写代码,比如计算出每隔100毫秒应该滚动多少,然后用一个计时器或者直接用一个递归在5秒内让这个按钮不断执行draw方法,可以实现但是显然比较麻烦。那Scroller就是帮助我们实现这个功能的类,它帮我们提供了一种算法计算出了每次draw的时候应该滚动到哪里而不需要我们自己去计算了。
Scroller的用法比较简单:
在初始化控件的时候就可以初始化Scroller,然后在需要自动滚动的时候调用startScroll方法,然后在View的computeScroll方法里(这个方法会在View每次draw的时候调用),调用Scroller的computeScrollOffset方法,这个方法就是实现了刚才说的计算并返回滚动是不是应该结束的boolean,并且把计算结果赋值到Scroller的currentX和currentY中。然后在View的computeScroll里直接调用scrollTo滚动到这点就行了。滚动完以后,调用invalidate,然后又会调用到draw方法,然后又会调用到computeScroll方法,接着又会调用Scroller的computeScrollOffset方法。
这里View的computeScroll方法和内部调用的invalidate方法形成了间接递归。
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
invalidate();
}
}
GestureDetector:
关于手势,我们可以在view的onTouchEvent里做一些处理,比如根据用户两次点击的间隔判断是不是双击,比如可以计算用户抬起手指时的速度以进行一些其它操作,比如down的时候记下手指的坐标然后手指在view上移动的时候相减得到手指滑动了多少距离,当然要考虑一些多点触控。
上面的方式当然可以,但是同样也是比较麻烦。于是GestureDetector被设计出来了,他帮我们进行了上述的操作,我们只要实现相关监听方法就行了。
GestureDetector的用法如下:
初始化代码:
mGestureDetector = new GestureDetector(new GestureListener());
mGestureDetector.setOnDoubleTapListener(new DoubleTapListener());
这两个参数的类都是自己实现的相关监听者类,实现了监听者接口,
//OnGestureListener监听
private class GestureListener implements GestureDetector.OnGestureListener{
// 用户轻触触摸屏,由1个MotionEvent ACTION_DOWN触发
public boolean onDown(MotionEvent e) {
Log.i("MyGesture", "onDown");
// Toast.makeText(MainActivity.this, "onDown", Toast.LENGTH_SHORT).show();
System.out.println("---------------------------onDown----------------");
return false;
}
/*
* 用户轻触触摸屏,尚未松开或拖动,由一个1个MotionEvent ACTION_DOWN触发
* 注意和onDown()的区别,强调的是没有松开或者拖动的状态
*
* 而onDown也是由一个MotionEventACTION_DOWN触发的,但是他没有任何限制,
* 也就是说当用户点击的时候,首先MotionEventACTION_DOWN,onDown就会执行,
* 如果在按下的瞬间没有松开或者是拖动的时候onShowPress就会执行,如果是按下的时间超过瞬间
* (这块我也不太清楚瞬间的时间差是多少,一般情况下都会执行onShowPress),拖动了,就不执行onShowPress。
*/
public void onShowPress(MotionEvent e) {
Log.i("MyGesture", "onShowPress");
// Toast.makeText(MainActivity.this, "onShowPress", Toast.LENGTH_SHORT).show();
System.out.println("---------------------------onShowPress----------------");
}
// 用户(轻触触摸屏后)松开,由一个1个MotionEvent ACTION_UP触发
///轻击一下屏幕,立刻抬起来,才会有这个触发
//从名子也可以看出,一次单独的轻击抬起操作,当然,如果除了Down以外还有其它操作,那就不再算是Single操作了,所以这个事件 就不再响应
public boolean onSingleTapUp(MotionEvent e) {
Log.i("MyGesture", "onSingleTapUp");
// Toast.makeText(MainActivity.this, "onSingleTapUp", Toast.LENGTH_SHORT).show();
System.out.println("---------------------------onSingleTapUp----------------");
return true;
}
// 用户按下触摸屏,并拖动,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE触发
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
Log.i("MyGesture", "onScroll:"+(e2.getX()-e1.getX()) +" "+distanceX);
// Toast.makeText(MainActivity.this, "onScroll", Toast.LENGTH_LONG).show();
System.out.println("---------------------------onScroll----------------"+"onScroll:"+(e2.getX()-e1.getX()) +" "+distanceX);
return true;
}
// 用户长按触摸屏,由多个MotionEvent ACTION_DOWN触发
public void onLongPress(MotionEvent e) {
Log.i("MyGesture", "onLongPress");
// Toast.makeText(MainActivity.this, "onLongPress", Toast.LENGTH_LONG).show();
System.out.println("---------------------------onLongPress----------------");
}
// 用户按下触摸屏、快速移动后松开,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
Log.i("MyGesture", "onFling");
// Toast.makeText(MainActivity.this, "onFling", Toast.LENGTH_LONG).show();
System.out.println("---------------------------onFling----------------");
return true;
}
};
//OnDoubleTapListener监听
private class DoubleTapListener implements GestureDetector.OnDoubleTapListener{
public boolean onSingleTapConfirmed(MotionEvent e) {
Log.i("MyGesture", "onSingleTapConfirmed");
// Toast.makeText(MainActivity.this, "onSingleTapConfirmed", Toast.LENGTH_LONG).show();
System.out.println("---------------------------onSingleTapConfirmed----------------");
return true;
}
public boolean onDoubleTap(MotionEvent e) {
Log.i("MyGesture", "onDoubleTap");
// Toast.makeText(MainActivity.this, "onDoubleTap", Toast.LENGTH_LONG).show();
System.out.println("---------------------------onDoubleTap----------------");
return true;
}
public boolean onDoubleTapEvent(MotionEvent e) {
Log.i("MyGesture", "onDoubleTapEvent");
// Toast.makeText(MainActivity.this, "onDoubleTapEvent", Toast.LENGTH_LONG).show();
System.out.println("---------------------------onDoubleTapEvent----------------"+e.getAction());
return true;
}
};
/*
* 在onTouch()方法中,我们调用GestureDetector的onTouchEvent()方法,将捕捉到的MotionEvent交给GestureDetector
* 来分析是否有合适的callback函数来处理用户的手势
*/
public boolean onTouch(View v, MotionEvent event) {
boolean result=mGestureDetector.onTouchEvent(event);
System.out.println("result---------------------:"+result);
return result;
}
VelocityTracker:
提供了速度的相关计算帮助。比如我想知道我此时的手指移动速度,如果自己计算的话,肯定会根据我手指移动的距离除以消耗的时间,当然要考虑其它很多因素,那VelocityTracker就是帮我们干这个的。
VelocityTracker的用法也很简单,如下:
也是在onTouch或者onInterceptTouchEvent等触摸时会调用的方法中加上截获相关事件:
mVelocityTracker.addMovement(event);
然后在ACTION_MOVE中:
verTracker.computeCurrentVelocity(1000, mMaxVelocity);
float velocityX = verTracker.getXVelocity(mPointerId);
float velocityY = verTracker.getYVelocity(mPointerId);
就得到了当前x轴和y轴的滑动速度。
OK,这三个帮助类介绍到这里,谢谢阅读。