追踪手势移动

编写:Andrwyw - 原文:http://developer.android.com/training/gestures/movement.html

本节课程讲述如何追踪手势移动。

每当当前的触摸位置、压力、大小发生变化时,ACTION_MOVE事件都会触发onTouchEvent()函数。正如检测常用的手势中描述的那样,触摸事件全部都记录在onTouchEvent()函数的MotionEvent参数中。

因为基于手指的触摸的交互方式并不总是非常精确,所以检测触摸事件更多的是基于手势移动,而非简单地基于触摸。为了帮助app区分基于移动的手势(如滑动)和非移动手势(如简单地点击),Android引入了“touch slop”的概念。Touch slop是指,在被识别为基于移动的手势前,用户触摸可移动的那一段像素距离。关于这一主题的更多讨论,可以在管理ViewGroup中的触摸事件中查看。

根据应用的需求,有多种追踪手势移动的方式可以选择。比如:

  • 追踪手指的起始和终止位置(比如,把屏幕上的对象从A点移动到B点)
  • 根据x、y轴坐标,追踪手指移动的方向。
  • 追踪历史状态。我们可以通过调用MotionEventgetHistorySize()方法,来获得一个手势的历史尺寸。我们可以通过移动事件的getHistorical<Value>系列函数,来获得事件之前的位置、尺寸、时间以及按压力(pressures)。当我们需要绘制用户手指痕迹时,历史状态非常有用,比如触摸绘图。查看MotionEvent来了解更多细节。
  • 追踪手指在触摸屏上滑过的速度。

追踪速度

我们可以简单地用基于距离,或(和)基于手指移动方向的移动手势。但是速度经常也是追踪手势特性的一个决定性因素,甚至是判断一个手势是否发生的依据。为了让计算速度更容易,Android提供了VelocityTracker类以及Support Library中的VelocityTrackerCompat类。VelocityTracker类可以帮助我们追踪触摸事件中的速度因素。如果速度是手势的一个判断标准,比如快速滑动(fling),那么这些类是很有用的。

下面是一个简单的例子,说明了VelocityTracker中API函数的用处。

  1. public class MainActivity extends Activity {
  2. private static final String DEBUG_TAG = "Velocity";
  3. ...
  4. private VelocityTracker mVelocityTracker = null;
  5. @Override
  6. public boolean onTouchEvent(MotionEvent event) {
  7. int index = event.getActionIndex();
  8. int action = event.getActionMasked();
  9. int pointerId = event.getPointerId(index);
  10. switch(action) {
  11. case MotionEvent.ACTION_DOWN:
  12. if(mVelocityTracker == null) {
  13. // Retrieve a new VelocityTracker object to watch the velocity of a motion.
  14. mVelocityTracker = VelocityTracker.obtain();
  15. }
  16. else {
  17. // Reset the velocity tracker back to its initial state.
  18. mVelocityTracker.clear();
  19. }
  20. // Add a user's movement to the tracker.
  21. mVelocityTracker.addMovement(event);
  22. break;
  23. case MotionEvent.ACTION_MOVE:
  24. mVelocityTracker.addMovement(event);
  25. // When you want to determine the velocity, call
  26. // computeCurrentVelocity(). Then call getXVelocity()
  27. // and getYVelocity() to retrieve the velocity for each pointer ID.
  28. mVelocityTracker.computeCurrentVelocity(1000);
  29. // Log velocity of pixels per second
  30. // Best practice to use VelocityTrackerCompat where possible.
  31. Log.d("", "X velocity: " +
  32. VelocityTrackerCompat.getXVelocity(mVelocityTracker,
  33. pointerId));
  34. Log.d("", "Y velocity: " +
  35. VelocityTrackerCompat.getYVelocity(mVelocityTracker,
  36. pointerId));
  37. break;
  38. case MotionEvent.ACTION_UP:
  39. case MotionEvent.ACTION_CANCEL:
  40. // Return a VelocityTracker object back to be re-used by others.
  41. mVelocityTracker.recycle();
  42. break;
  43. }
  44. return true;
  45. }
  46. }

Note: 需要注意的是,我们应该在ACTION_MOVE事件,而不是在ACTION_UP事件后计算速度。在ACTION_UP事件之后,计算x、y方向上的速度都会是0。