onTouchEvent同样也是在view中定义的一个方法。处理传递到view 的手势事件。通过MotionEvent的getAction()方法来获取Touch事件的类型,类型包括ACTION_DOWN,ACTION_MOVE,ACTION_UP,ACTION_CANCEL等事件。其中ACTION_DOWN是指按下触摸屏,ACTION_MOVE是指按下触摸屏后移动受力点,ACTION_UP则是指松 开触摸屏,ACTION_CANCEL不会由用户直接触发。

贴上View.onTouchEvent的android 5.0源代码

  1. public boolean onTouchEvent(MotionEvent event) {
  2. final float x = event.getX();
  3. final float y = event.getY();
  4. final int viewFlags = mViewFlags;
  5.  
  6. if ((viewFlags & ENABLED_MASK) == DISABLED) {
  7. if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
  8. setPressed(false);
  9. }
  10. // A disabled view that is clickable still consumes the touch
  11. // events, it just doesn't respond to them.
  12. return (((viewFlags & CLICKABLE) == CLICKABLE ||
  13. (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE));
  14. }
  15.  
  16. if (mTouchDelegate != null) {
  17. if (mTouchDelegate.onTouchEvent(event)) {
  18. return true;
  19. }
  20. }
  21.  
  22. if (((viewFlags & CLICKABLE) == CLICKABLE ||
  23. (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
  24. switch (event.getAction()) {
  25. case MotionEvent.ACTION_UP:
  26. boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;
  27. if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {
  28. // take focus if we don't have it already and we should in
  29. // touch mode.
  30. boolean focusTaken = false;
  31. if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
  32. focusTaken = requestFocus();
  33. }
  34.  
  35. if (prepressed) {
  36. // The button is being released before we actually
  37. // showed it as pressed. Make it show the pressed
  38. // state now (before scheduling the click) to ensure
  39. // the user sees it.
  40. setPressed(true, x, y);
  41. }
  42.  
  43. if (!mHasPerformedLongPress) {
  44. // This is a tap, so remove the longpress check
  45. removeLongPressCallback();
  46.  
  47. // Only perform take click actions if we were in the pressed state
  48. if (!focusTaken) {
  49. // Use a Runnable and post this rather than calling
  50. // performClick directly. This lets other visual state
  51. // of the view update before click actions start.
  52. if (mPerformClick == null) {
  53. mPerformClick = new PerformClick();
  54. }
  55. if (!post(mPerformClick)) {
  56. performClick();
  57. }
  58. }
  59. }
  60.  
  61. if (mUnsetPressedState == null) {
  62. mUnsetPressedState = new UnsetPressedState();
  63. }
  64.  
  65. if (prepressed) {
  66. postDelayed(mUnsetPressedState,
  67. ViewConfiguration.getPressedStateDuration());
  68. } else if (!post(mUnsetPressedState)) {
  69. // If the post failed, unpress right now
  70. mUnsetPressedState.run();
  71. }
  72.  
  73. removeTapCallback();
  74. }
  75. break;
  76.  
  77. case MotionEvent.ACTION_DOWN:
  78. mHasPerformedLongPress = false;
  79.  
  80. if (performButtonActionOnTouchDown(event)) {
  81. break;
  82. }
  83.  
  84. // Walk up the hierarchy to determine if we're inside a scrolling container.
  85. boolean isInScrollingContainer = isInScrollingContainer();
  86.  
  87. // For views inside a scrolling container, delay the pressed feedback for
  88. // a short period in case this is a scroll.
  89. if (isInScrollingContainer) {
  90. mPrivateFlags |= PFLAG_PREPRESSED;
  91. if (mPendingCheckForTap == null) {
  92. mPendingCheckForTap = new CheckForTap();
  93. }
  94. mPendingCheckForTap.x = event.getX();
  95. mPendingCheckForTap.y = event.getY();
  96. postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
  97. } else {
  98. // Not inside a scrolling container, so show the feedback right away
  99. setPressed(true, x, y);
  100. checkForLongClick(0);
  101. }
  102. break;
  103.  
  104. case MotionEvent.ACTION_CANCEL:
  105. setPressed(false);
  106. removeTapCallback();
  107. removeLongPressCallback();
  108. break;
  109.  
  110. case MotionEvent.ACTION_MOVE:
  111. drawableHotspotChanged(x, y);
  112.  
  113. // Be lenient about moving outside of buttons
  114. if (!pointInView(x, y, mTouchSlop)) {
  115. // Outside button
  116. removeTapCallback();
  117. if ((mPrivateFlags & PFLAG_PRESSED) != 0) {
  118. // Remove any future long press/tap checks
  119. removeLongPressCallback();
  120.  
  121. setPressed(false);
  122. }
  123. }
  124. break;
  125. }
  126.  
  127. return true;
  128. }
  129.  
  130. return false;
  131. }

随后,在onTouch()方法中,我们调用GestureDetector的onTouchEvent()方法,将捕捉到的MotionEvent交给 GestureDetector 来分析是否有合适的callback函数来处理用户的手势。

贴上GestureDetector.onTouchEvent的android 5.0的源码:

  1. public boolean onTouchEvent(MotionEvent ev) {
  2. if (mInputEventConsistencyVerifier != null) {
  3. mInputEventConsistencyVerifier.onTouchEvent(ev, 0);
  4. }
  5.  
  6. final int action = ev.getAction();
  7.  
  8. if (mVelocityTracker == null) {
  9. mVelocityTracker = VelocityTracker.obtain();
  10. }
  11. mVelocityTracker.addMovement(ev);
  12.  
  13. final boolean pointerUp =
  14. (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP;
  15. final int skipIndex = pointerUp ? ev.getActionIndex() : -1;
  16.  
  17. // Determine focal point
  18. float sumX = 0, sumY = 0;
  19. final int count = ev.getPointerCount();
  20. for (int i = 0; i < count; i++) {
  21. if (skipIndex == i) continue;
  22. sumX += ev.getX(i);
  23. sumY += ev.getY(i);
  24. }
  25. final int div = pointerUp ? count - 1 : count;
  26. final float focusX = sumX / div;
  27. final float focusY = sumY / div;
  28.  
  29. boolean handled = false;
  30.  
  31. switch (action & MotionEvent.ACTION_MASK) {
  32. case MotionEvent.ACTION_POINTER_DOWN:
  33. mDownFocusX = mLastFocusX = focusX;
  34. mDownFocusY = mLastFocusY = focusY;
  35. // Cancel long press and taps
  36. cancelTaps();
  37. break;
  38.  
  39. case MotionEvent.ACTION_POINTER_UP:
  40. mDownFocusX = mLastFocusX = focusX;
  41. mDownFocusY = mLastFocusY = focusY;
  42.  
  43. // Check the dot product of current velocities.
  44. // If the pointer that left was opposing another velocity vector, clear.
  45. mVelocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
  46. final int upIndex = ev.getActionIndex();
  47. final int id1 = ev.getPointerId(upIndex);
  48. final float x1 = mVelocityTracker.getXVelocity(id1);
  49. final float y1 = mVelocityTracker.getYVelocity(id1);
  50. for (int i = 0; i < count; i++) {
  51. if (i == upIndex) continue;
  52.  
  53. final int id2 = ev.getPointerId(i);
  54. final float x = x1 * mVelocityTracker.getXVelocity(id2);
  55. final float y = y1 * mVelocityTracker.getYVelocity(id2);
  56.  
  57. final float dot = x + y;
  58. if (dot < 0) {
  59. mVelocityTracker.clear();
  60. break;
  61. }
  62. }
  63. break;
  64.  
  65. case MotionEvent.ACTION_DOWN:
  66. if (mDoubleTapListener != null) {
  67. boolean hadTapMessage = mHandler.hasMessages(TAP);
  68. if (hadTapMessage) mHandler.removeMessages(TAP);
  69. if ((mCurrentDownEvent != null) && (mPreviousUpEvent != null) && hadTapMessage &&
  70. isConsideredDoubleTap(mCurrentDownEvent, mPreviousUpEvent, ev)) {
  71. // This is a second tap
  72. mIsDoubleTapping = true;
  73. // Give a callback with the first tap of the double-tap
  74. handled |= mDoubleTapListener.onDoubleTap(mCurrentDownEvent);
  75. // Give a callback with down event of the double-tap
  76. handled |= mDoubleTapListener.onDoubleTapEvent(ev);
  77. } else {
  78. // This is a first tap
  79. mHandler.sendEmptyMessageDelayed(TAP, DOUBLE_TAP_TIMEOUT);
  80. }
  81. }
  82.  
  83. mDownFocusX = mLastFocusX = focusX;
  84. mDownFocusY = mLastFocusY = focusY;
  85. if (mCurrentDownEvent != null) {
  86. mCurrentDownEvent.recycle();
  87. }
  88. mCurrentDownEvent = MotionEvent.obtain(ev);
  89. mAlwaysInTapRegion = true;
  90. mAlwaysInBiggerTapRegion = true;
  91. mStillDown = true;
  92. mInLongPress = false;
  93. mDeferConfirmSingleTap = false;
  94.  
  95. if (mIsLongpressEnabled) {
  96. mHandler.removeMessages(LONG_PRESS);
  97. mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime()
  98. + TAP_TIMEOUT + LONGPRESS_TIMEOUT);
  99. }
  100. mHandler.sendEmptyMessageAtTime(SHOW_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT);
  101. handled |= mListener.onDown(ev);
  102. break;
  103.  
  104. case MotionEvent.ACTION_MOVE:
  105. if (mInLongPress) {
  106. break;
  107. }
  108. final float scrollX = mLastFocusX - focusX;
  109. final float scrollY = mLastFocusY - focusY;
  110. if (mIsDoubleTapping) {
  111. // Give the move events of the double-tap
  112. handled |= mDoubleTapListener.onDoubleTapEvent(ev);
  113. } else if (mAlwaysInTapRegion) {
  114. final int deltaX = (int) (focusX - mDownFocusX);
  115. final int deltaY = (int) (focusY - mDownFocusY);
  116. int distance = (deltaX * deltaX) + (deltaY * deltaY);
  117. if (distance > mTouchSlopSquare) {
  118. handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
  119. mLastFocusX = focusX;
  120. mLastFocusY = focusY;
  121. mAlwaysInTapRegion = false;
  122. mHandler.removeMessages(TAP);
  123. mHandler.removeMessages(SHOW_PRESS);
  124. mHandler.removeMessages(LONG_PRESS);
  125. }
  126. if (distance > mDoubleTapTouchSlopSquare) {
  127. mAlwaysInBiggerTapRegion = false;
  128. }
  129. } else if ((Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)) {
  130. handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
  131. mLastFocusX = focusX;
  132. mLastFocusY = focusY;
  133. }
  134. break;
  135.  
  136. case MotionEvent.ACTION_UP:
  137. mStillDown = false;
  138. MotionEvent currentUpEvent = MotionEvent.obtain(ev);
  139. if (mIsDoubleTapping) {
  140. // Finally, give the up event of the double-tap
  141. handled |= mDoubleTapListener.onDoubleTapEvent(ev);
  142. } else if (mInLongPress) {
  143. mHandler.removeMessages(TAP);
  144. mInLongPress = false;
  145. } else if (mAlwaysInTapRegion) {
  146. handled = mListener.onSingleTapUp(ev);
  147. if (mDeferConfirmSingleTap && mDoubleTapListener != null) {
  148. mDoubleTapListener.onSingleTapConfirmed(ev);
  149. }
  150. } else {
  151.  
  152. // A fling must travel the minimum tap distance
  153. final VelocityTracker velocityTracker = mVelocityTracker;
  154. final int pointerId = ev.getPointerId(0);
  155. velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
  156. final float velocityY = velocityTracker.getYVelocity(pointerId);
  157. final float velocityX = velocityTracker.getXVelocity(pointerId);
  158.  
  159. if ((Math.abs(velocityY) > mMinimumFlingVelocity)
  160. || (Math.abs(velocityX) > mMinimumFlingVelocity)){
  161. handled = mListener.onFling(mCurrentDownEvent, ev, velocityX, velocityY);
  162. }
  163. }
  164. if (mPreviousUpEvent != null) {
  165. mPreviousUpEvent.recycle();
  166. }
  167. // Hold the event we obtained above - listeners may have changed the original.
  168. mPreviousUpEvent = currentUpEvent;
  169. if (mVelocityTracker != null) {
  170. // This may have been cleared when we called out to the
  171. // application above.
  172. mVelocityTracker.recycle();
  173. mVelocityTracker = null;
  174. }
  175. mIsDoubleTapping = false;
  176. mDeferConfirmSingleTap = false;
  177. mHandler.removeMessages(SHOW_PRESS);
  178. mHandler.removeMessages(LONG_PRESS);
  179. break;
  180.  
  181. case MotionEvent.ACTION_CANCEL:
  182. cancel();
  183. break;
  184. }
  185.  
  186. if (!handled && mInputEventConsistencyVerifier != null) {
  187. mInputEventConsistencyVerifier.onUnhandledEvent(ev, 0);
  188. }
  189. return handled;
  190. }

原理还不太清楚,只能先贴上代码,望各位大神指教,谢谢!

Android L(5.0)源码之手势识别onTouchEvent的更多相关文章

  1. [Android FrameWork 6.0源码学习] View的重绘过程之WindowManager的addView方法

    博客首页:http://www.cnblogs.com/kezhuang/p/关于Activity的contentView的构建过程,我在我的博客中已经分析过了,不了解的可以去看一下<[Andr ...

  2. [Android FrameWork 6.0源码学习] LayoutInflater 类分析

    LayoutInflater是用来解析XML布局文件,然后生成对象的ViewTree的工具类.是这个工具类的存在,才能让我们写起Layout来那么省劲. 我们接下来进去刨析,看看里边的奥秘 //调用i ...

  3. [Android FrameWork 6.0源码学习] View的重绘过程之Draw

    View绘制的三部曲,测量,布局,绘画现在我们分析绘画部分测量和布局 在前两篇文章中已经分析过了.不了解的可以去我的博客里找一下 下面进入正题,开始分析调用以及函数原理 private void pe ...

  4. [Android FrameWork 6.0源码学习] ViewGroup的addView函数分析

    Android中整个的View的组装是采用组合模式. ViewGroup就相当与树根,各种Layout就相当于枝干,各种子View,就相当于树叶. 至于View类.我们就当它是个种子吧.哈哈! Vie ...

  5. [Android FrameWork 6.0源码学习] View的重绘过程

    View绘制的三部曲,  测量,布局,绘画今天我们分析测量过程 view的测量是从ViewRootImpl发起的,View需要重绘,都是发送请求给ViewRootImpl,然后他组织重绘在重绘的过程中 ...

  6. [Android FrameWork 6.0源码学习] Window窗口类分析

    了解这一章节,需要先了解LayoutInflater这个工具类,我以前分析过:http://www.cnblogs.com/kezhuang/p/6978783.html Window是Activit ...

  7. [Android FrameWork 6.0源码学习] View的重绘过程之Layout

    View绘制的三部曲,测量,布局,绘画现在我们分析布局部分测量部分在上篇文章中已经分析过了.不了解的可以去我的博客里找一下 View的布局和测量一样,都是从ViewRootImpl中发起,ViewRo ...

  8. [Android FrameWork 6.0源码学习] View的重绘ViewRootImpl的setView方法

    博客首页:http://www.cnblogs.com/kezhuang/p/ 本篇文章来分析一下WindowManager的后续工作,也就是ViewRootImpl的setView函数的工作 /i* ...

  9. Android音乐播放器源码(歌词.均衡器.收藏.qq5.0菜单.通知)

    一款Android音乐播放器源码,基本功能都实现了 qq5.0菜单(歌词.均衡器.收藏.qq5.0菜单.通知) 只有向右滑动出现,菜单键和指定按钮都还没有添加. 源码下载:http://code.66 ...

随机推荐

  1. android 检测是否插入U盘方法之一

    本方法是检测文件/proc/partitions. import java.io.*; File Usbfile = new File("/proc/partitions");if ...

  2. JavaScript(2)——对象属性、原型与原型链

    对象属性.原型与原型链 哈哈哈,我的第二篇博客哟,说的是对象属性.原型与原型链.可能这些只是某些小点串联起来的,逻辑性没有很强.所以会对文章的可读性和理解性带来一些困扰.不过,今天我又前进了那么一小步 ...

  3. ARC属性中还能使用assign,copy,retain这些关键字吗

    http://blog.sina.com.cn/s/blog_6531b9b80101c6cr.html      很早以前比较弱,网上不知道哪里看了篇博文,留下了ARC属性中不能使用retain关键 ...

  4. 学习笔记——模板模式Template

    模板模式,主要是利用多态来实现具体算法和父类逻辑的松耦合.父类中TemplateMethod内部定义了相应的算法操作顺序,子类负责实现相应的具体实现. 举例: 项目中曾遇到过一个需求,叫做高级价格体系 ...

  5. VirtualBox 复制vdi文件和修改vdi的uuid

    1.复制vdi文件:VBoxManage clonehd 因为VirtualBox不允许注册重复的uuid,而每个vdi文件都有一个唯一的uuid.所以要想拷贝一份vdi文件再次在VBOX中注册,简单 ...

  6. 交换机VLAN、 TRUNK 、VTP 配置

    交换机VLAN. TRUNK .VTP 配置 1. 配置 CISCO 二层交换机的IP 地址(catalyst 2950 为例) SW1(config)#int vlan 1 //进入管理接口inte ...

  7. Android SERVICE后台服务进程的自启动和保持

    Service组件在android开发中经常遇到,其经常作为后台服务,需要始终保持运行,负责处理一些必要(见不得人)的任务.而一些安全软件,如360等,会有结束进程的功能,如果不做Service的保持 ...

  8. Segment,Path,Ring和Polyline对象

    Segment几何对象   Segment对象是一个有起点和终点的“线“,也就是说Segement只有两个点,至于两点之间的线是直的,还是曲的,需要其余的参数定义.所以Segment是由起点,终点和参 ...

  9. CentOS 6.3下NTP服务安装和配置

    测试环境: NTPserver 192.168.1.252 NTPclient 192.168.1.251 准备工作: 关闭selinux: vi /etc/selinux/config SELINU ...

  10. sql查询技巧,按时间分段进行分组,每半小时一组统计组内记录数量

    今天拿到一个查询需求,需要统计某一天各个时间段内的记录数量. 具体是统计某天9:00至22:00时间段,每半小时内订单的数量,最后形成的数据形式如下: 时间段          订单数 9:00~9: ...