Android事件分发流程分析证明(1)

2016-11-21 20:51 评论 0 条

摘要:

为了掌握手势冲突的解决办法,必须了解清楚Android事件分发的流程。事件分发的技术文档看了比较多,看完了感觉还是不理解,为了验证文档的结论,突发奇想地想要用实验的方式证明,于是有了这篇文章。事件分发流程分为View和ViewGroup两种,相关的方法是dispatchTouchEvent、onTouchEvent和onInterceptTouchEvent以及requestDisallowInterceptTouchEvent,前面两个方法继承于View,后面两个方法继承ViewGroup。
event-dispatch-1
整备材料:

(1)重写的View或ViewGroup:MyImageView、MyButton、MyLinearLayout和MyRelativeLayout

  1. /** 
  2.  *重写View的dispatchTouchEvent和onTouchEvent方法 
  3.  */  
  4.  @Override  
  5.     public boolean dispatchTouchEvent(MotionEvent event) {  
  6.         boolean flag = super.dispatchTouchEvent(event);  
  7. //        if (event.getAction() == MotionEvent.ACTION_DOWN)  
  8. //            Log.d(TAG, "dispatchTouchEvent: " + flag);  
  9.         switch (event.getAction()) {  
  10.             case MotionEvent.ACTION_DOWN:  
  11.                 Log.d(TAG, "dispatchTouchEvent: ACTION_DOWN " + flag);  
  12.                 break;  
  13.             case MotionEvent.ACTION_MOVE:  
  14.                 Log.d(TAG, "dispatchTouchEvent: ACTION_MOVE " + flag);  
  15.                 break;  
  16.             case MotionEvent.ACTION_UP:  
  17.                 Log.d(TAG, "dispatchTouchEvent: ACTION_UP " + flag);  
  18.                 break;  
  19.         }  
  20.         return flag;  
  21.     }  
  22.   
  23.     @Override  
  24.     public boolean onTouchEvent(MotionEvent event) {  
  25.         boolean flag = super.onTouchEvent(event);  
  26. //        if (event.getAction() == MotionEvent.ACTION_DOWN)  
  27. //            Log.d(TAG, "onTouchEvent: " + flag);  
  28.         switch (event.getAction()) {  
  29.             case MotionEvent.ACTION_DOWN:  
  30.                 Log.d(TAG, "onTouchEvent: ACTION_DOWN " + flag);  
  31.                 break;  
  32.             case MotionEvent.ACTION_MOVE:  
  33.                 Log.d(TAG, "onTouchEvent: ACTION_MOVE " + flag);  
  34.                 break;  
  35.             case MotionEvent.ACTION_UP:  
  36.                 Log.d(TAG, "onTouchEvent: ACTION_UP " + flag);  
  37.                 break;  
  38.         }  
  39.         return flag;  
  40.     }  
  1. /** 
  2.  *重写ViewGroup的dispatchTouchEvent和onTouchEvent方法外,同时重写onInterceptTouchEvent、requestDisallowInterceptTouchEvent方法 
  3.  */  
  4.   @Override  
  5.     public boolean onInterceptTouchEvent(MotionEvent ev) {  
  6.         boolean flag = super.onInterceptTouchEvent(ev);  
  7. //        if (ev.getAction()==MotionEvent.ACTION_DOWN)  
  8. //        Log.d(TAG, "onInterceptTouchEvent: "+flag);  
  9.         switch (ev.getAction()) {  
  10.             case MotionEvent.ACTION_DOWN:  
  11.                 Log.d(TAG, "onInterceptTouchEvent: ACTION_DOWN " + flag);  
  12.                 break;  
  13.             case MotionEvent.ACTION_MOVE:  
  14.                 Log.d(TAG, "onInterceptTouchEvent: ACTION_MOVE " + flag);  
  15.                 break;  
  16.             case MotionEvent.ACTION_UP:  
  17.                 Log.d(TAG, "onInterceptTouchEvent: ACTION_UP " + flag);  
  18.                 break;  
  19.         }  
  20.         return flag;  
  21.     }  
  22.   
  23.     @Override  
  24.     public boolean dispatchTouchEvent(MotionEvent event) {  
  25.         boolean flag = super.dispatchTouchEvent(event);  
  26. //        if (event.getAction()==MotionEvent.ACTION_DOWN)  
  27. //        Log.d(TAG, "dispatchTouchEvent: " + flag);  
  28.         switch (event.getAction()) {  
  29.             case MotionEvent.ACTION_DOWN:  
  30.                 Log.d(TAG, "dispatchTouchEvent: ACTION_DOWN " + flag);  
  31.                 break;  
  32.             case MotionEvent.ACTION_MOVE:  
  33.                 Log.d(TAG, "dispatchTouchEvent: ACTION_MOVE " + flag);  
  34.                 break;  
  35.             case MotionEvent.ACTION_UP:  
  36.                 Log.d(TAG, "dispatchTouchEvent: ACTION_UP " + flag);  
  37.                 break;  
  38.         }  
  39.         return flag;  
  40.     }  
  41.   
  42.     @Override  
  43.     public boolean onTouchEvent(MotionEvent event) {  
  44.         boolean flag = super.onTouchEvent(event);  
  45. //        if (event.getAction()==MotionEvent.ACTION_DOWN)  
  46. //        Log.d(TAG, "onTouchEvent: "+flag);  
  47.         switch (event.getAction()) {  
  48.             case MotionEvent.ACTION_DOWN:  
  49.                 Log.d(TAG, "onTouchEvent: ACTION_DOWN " + flag);  
  50.                 break;  
  51.             case MotionEvent.ACTION_MOVE:  
  52.                 Log.d(TAG, "onTouchEvent: ACTION_MOVE " + flag);  
  53.                 break;  
  54.             case MotionEvent.ACTION_UP:  
  55.                 Log.d(TAG, "onTouchEvent: ACTION_UP " + flag);  
  56.                 break;  
  57.         }  
  58.         return flag;  
  59.     }  
  60.   
  61.     @Override  
  62.     public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {  
  63.         super.requestDisallowInterceptTouchEvent(disallowIntercept);  
  64.         Log.d(TAG, "requestDisallowInterceptTouchEvent: ");  
  65.     }  

(2)设置布局文件:activity_event_dispatch.xml

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <cn.teachcourse.view.MyRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:tools="http://schemas.android.com/tools"  
  4.     android:id="@+id/activity_event_dispatch"  
  5.     android:layout_width="match_parent"  
  6.     android:layout_height="match_parent"  
  7.     android:paddingBottom="@dimen/activity_vertical_margin"  
  8.     android:paddingLeft="@dimen/activity_horizontal_margin"  
  9.     android:paddingRight="@dimen/activity_horizontal_margin"  
  10.     android:paddingTop="@dimen/activity_vertical_margin"  
  11.     tools:context="cn.teachcourse.view.EventDispatchActivity">  
  12.   
  13.     <cn.teachcourse.view.MyImageView  
  14.         android:id="@+id/dispatch_iv"  
  15.         android:layout_width="wrap_content"  
  16.         android:layout_height="wrap_content"  
  17.         android:src="@drawable/beautiful_girl" />  
  18.   
  19.     <cn.teachcourse.view.MyLinearlayout  
  20.         android:id="@+id/dispatch_ll"  
  21.         android:layout_width="match_parent"  
  22.         android:layout_height="100dp"  
  23.         android:layout_below="@+id/dispatch_iv"  
  24.         android:layout_marginTop="@dimen/activity_horizontal_margin"  
  25.         android:background="@drawable/default_bg">  
  26.   
  27.     </cn.teachcourse.view.MyLinearlayout>  
  28.   
  29.     <cn.teachcourse.view.MyLinearlayout  
  30.         android:id="@+id/dispatch_event_ll"  
  31.         android:layout_width="match_parent"  
  32.         android:layout_height="wrap_content"  
  33.         android:orientation="vertical"  
  34.         android:layout_below="@+id/dispatch_ll"  
  35.         android:layout_marginTop="@dimen/activity_horizontal_margin">  
  36.   
  37.         <cn.teachcourse.view.MyImageView  
  38.             android:id="@+id/dispatch_event_iv"  
  39.             android:layout_width="wrap_content"  
  40.             android:layout_height="wrap_content"  
  41.             android:clickable="false"  
  42.             android:src="@drawable/beautiful_girl" />  
  43.   
  44.         <cn.teachcourse.view.MyButton  
  45.             android:id="@+id/dispatch_event_btn"  
  46.             android:layout_width="match_parent"  
  47.             android:layout_height="wrap_content"  
  48.             android:text="@string/app_name"  
  49.             android:layout_margin="@dimen/activity_vertical_margin" />  
  50.   
  51.     </cn.teachcourse.view.MyLinearlayout>  
  52.   
  53. </cn.teachcourse.view.MyRelativeLayout>  

(3)通过鼠标在屏幕上滑动,查看log打印的结果,得出实验的结论。

实验一:证明事件传递由外到内,事件响应由内到外

与事件传递相关的方法是:

(1)dispatchTouchEvent:传递当前触摸屏幕的事件给下一个target view,或者当前view(如果当前view是target view)

return true,表示触摸屏幕的事件被当前view处理,否则交由下一个target view处理。

MyButton、MyImageView分别继承Button和ImageView,重写View的dispatchTouchEvent、onTouchEvent方法,滑动MyButton和MyImageView,查看log打印的结果:

  1. /** 
  2.  *MyButton打印结果 
  3.  */  
  4. D/MyRelativeLayout: onInterceptTouchEvent: ACTION_DOWN false  
  5. D/MyLinearlayout: onInterceptTouchEvent: ACTION_DOWN false  
  6. D/MyButton: onTouchEvent: ACTION_DOWN true  
  7. D/MyButton: dispatchTouchEvent: ACTION_DOWN true  
  8. D/MyLinearlayout: dispatchTouchEvent: ACTION_DOWN true  
  9. D/MyRelativeLayout: dispatchTouchEvent: ACTION_DOWN true  
  10. D/MyRelativeLayout: onInterceptTouchEvent: ACTION_MOVE true  
  11. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE true  
  12. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  13. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  14. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  15. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  16. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  17. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  18. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  19. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  20. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  21. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  22. D/MyRelativeLayout: onTouchEvent: ACTION_UP false  
  23. D/MyRelativeLayout: dispatchTouchEvent: ACTION_UP false  
  1. /** 
  2.  *MyImageView打印结果 
  3.  */  
  4. D/MyRelativeLayout: onInterceptTouchEvent: ACTION_DOWN false  
  5. D/MyLinearlayout: onInterceptTouchEvent: ACTION_DOWN false  
  6. D/MyImageView: onTouchEvent: ACTION_DOWN false  
  7. D/MyImageView: dispatchTouchEvent: ACTION_DOWN false  
  8. D/MyLinearlayout: onTouchEvent: ACTION_DOWN false  
  9. D/MyLinearlayout: dispatchTouchEvent: ACTION_DOWN false  
  10. D/MyRelativeLayout: onTouchEvent: ACTION_DOWN false  
  11. D/MyRelativeLayout: dispatchTouchEvent: ACTION_DOWN false  

为什么MyImageView打印结果和MyButton不同?

原因是MyImageView继承ImageView,ImageView默认clickable=false,类似TextView默认无法点击一样。想要让MyImageView和MyButton打印一样的结果,将clickable设置为true即可。

结论:
从实验一,我们大概可以看到滑动MyImageView控件后,事件传递的流程:MyRelativeLayout——>MyLinearLayout——>MyButton(或MyImageView)——>MyLinearLayout——>MyRelativeLayout,根据视图结构的外层向内层传递,然后再由内层向外层响应。

实验二:证明滑动手势伴随一个ACTION_DOWN、多个ACTION_MOVE和一个ACTION_UP

在实验一中,我们将MyImageView的clickable属性设置为true,然后继续在该控件上不停的滑动,查看log的打印结果:

  1. D/MyRelativeLayout: onInterceptTouchEvent: ACTION_DOWN false  
  2. D/MyLinearlayout: onInterceptTouchEvent: ACTION_DOWN false  
  3. D/MyImageView: onTouchEvent: ACTION_DOWN true  
  4. D/MyImageView: dispatchTouchEvent: ACTION_DOWN true  
  5. D/MyLinearlayout: dispatchTouchEvent: ACTION_DOWN true  
  6. D/MyRelativeLayout: dispatchTouchEvent: ACTION_DOWN true  
  7. D/MyRelativeLayout: onInterceptTouchEvent: ACTION_MOVE true  
  8. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE true  
  9.   
  10. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  11. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  12. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  13. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  14. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  15. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  16. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  17. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  18. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  19. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  20. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  21. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  22. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  23. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  24. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  25. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  26. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  27. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  28. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  29. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  30. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  31. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  32. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  33. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  34. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  35. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  36. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  37. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  38. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  39. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  40. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  41. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  42. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  43. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  44. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  45. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  46. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  47. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  48. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  49. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  50. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  51. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  52. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  53. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  54. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  55. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  56. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  57. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  58. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  59. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  60. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  61. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  62. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  63. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  64. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  65. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  66. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  67. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  68. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  69. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  70. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  71. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  72. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  73. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  74. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  75. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  76. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  77. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  78. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  79. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  80. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  81. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  82. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  83. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  84. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  85. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  86. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  87. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  88. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  89. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  90. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  91. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  92. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  93. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  94. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  95. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  96. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  97. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  98. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  99. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  100. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  101. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  102. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  103. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  104. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  105. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  106. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  107. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  108. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  109. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  110. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  111. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  112. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  113. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  114. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  115. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  116. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  117. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  118. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  119. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  120. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  121. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  122. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  123. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  124. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  125. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  126.   
  127. D/MyRelativeLayout: onTouchEvent: ACTION_UP false  
  128. D/MyRelativeLayout: dispatchTouchEvent: ACTION_UP false  

结论:打印的结果和MyButton的顺序完全一样,同时分析可以看出,中间全部重复ACTION_MOVE这个动作,只有开始出现ACTION_DOWN,结束出现了ACTION_UP,说明滑动手势伴随一个ACTION_DOWN、多个ACTION_MOVE和一个ACTION_UP,了解这个对我们有什么好处呢?不急,后面慢慢说呀。

实验三:证明onInterceptTouchEvent返回true,禁止事件继续传递

onInterceptTouchEvent和requestDisallowInterceptTouchEvent继承属于ViewGroup,查看源码熟悉它们的用法:

  1. /** 
  2.      * Implement this method to intercept all touch screen motion events.  This 
  3.      * allows you to watch events as they are dispatched to your children, and 
  4.      * take ownership of the current gesture at any point. 
  5.      * 
  6.      * <p>Using this function takes some care, as it has a fairly complicated 
  7.      * interaction with {@link View#onTouchEvent(MotionEvent) 
  8.      * View.onTouchEvent(MotionEvent)}, and using it requires implementing 
  9.      * that method as well as this one in the correct way.  Events will be 
  10.      * received in the following order: 
  11.      * 
  12.      * <ol> 
  13.      * <li> You will receive the down event here. 
  14.      * <li> The down event will be handled either by a child of this view 
  15.      * group, or given to your own onTouchEvent() method to handle; this means 
  16.      * you should implement onTouchEvent() to return true, so you will 
  17.      * continue to see the rest of the gesture (instead of looking for 
  18.      * a parent view to handle it).  Also, by returning true from 
  19.      * onTouchEvent(), you will not receive any following 
  20.      * events in onInterceptTouchEvent() and all touch processing must 
  21.      * happen in onTouchEvent() like normal. 
  22.      * <li> For as long as you return false from this function, each following 
  23.      * event (up to and including the final up) will be delivered first here 
  24.      * and then to the target's onTouchEvent(). 
  25.      * <li> If you return true from here, you will not receive any 
  26.      * following events: the target view will receive the same event but 
  27.      * with the action {@link MotionEvent#ACTION_CANCEL}, and all further 
  28.      * events will be delivered to your onTouchEvent() method and no longer 
  29.      * appear here. 
  30.      * </ol> 
  31.      * 
  32.      * @param ev The motion event being dispatched down the hierarchy. 
  33.      * @return Return true to steal motion events from the children and have 
  34.      * them dispatched to this ViewGroup through onTouchEvent(). 
  35.      * The current target will receive an ACTION_CANCEL event, and no further 
  36.      * messages will be delivered here. 
  37.      */  
  38.     public boolean onInterceptTouchEvent(MotionEvent ev) {  
  39.         return false;  
  40.     }  

翻译的大概意思:实现onInterceptTouchEvent方法拦截所有触摸屏幕的事件,该方法允许你观察被发送给子控件的事件,并获取当前触摸屏幕手势的所有权。

(1)这里首先获取触摸屏幕ACTION_DOWN事件

(2)ACTION_DOWN事件可以被当前ViewGroup的子控件处理,也可以传递给当前ViewGroup的onTouchEvent()方法处理;也就是说你应该实现onTouchEvent()方法并返回true,于是你将会继续观察到手势的其他事件。同时,通过onTouchEvent返回true,你将无法在onInterceptTouchEvent方法中接收任何ACTION_DOWN之外的事件;target view将会接收到相同的事件,只是伴随着ACTION_CANCEL事件,后面所有的事件将会被传递到onTouchEvent()方法,不会再在这里出现。

(3)只要该方法返回false,接下来的每一个事件都将会首先传递到这里,然后在传递到target的onTouchEvent()方法

(4)如果该方法返回true,你将无法接收接下来的任何一个事件;target view将会接收到相同的事件,只是伴随着ACTION_CANCEL事件,后面所有的事件将会被传递到onTouchEvent()方法,不会再在这里出现。

为了验证第(3)点阐述的两层意思,我们选择重写的MyRelativeLayout控件,第一层意思:让当前的MyRelativeLayout的onTouchEvent返回true,结果是否可以证明该方法里可以接收ACTION_DOWN之外的其它事件,查看log打印结果:

  1. @Override  
  2.     public boolean onTouchEvent(MotionEvent event) {  
  3.         /** 
  4.      *默认flag=false,返回true 
  5.      */  
  6.         boolean flag = super.onTouchEvent(event);  
  7.   
  8.         switch (event.getAction()) {  
  9.             case MotionEvent.ACTION_DOWN:  
  10.                 Log.d(TAG, "onTouchEvent: ACTION_DOWN " + flag);  
  11.                 break;  
  12.             case MotionEvent.ACTION_MOVE:  
  13.                 Log.d(TAG, "onTouchEvent: ACTION_MOVE " + flag);  
  14.                 break;  
  15.             case MotionEvent.ACTION_UP:  
  16.                 Log.d(TAG, "onTouchEvent: ACTION_UP " + flag);  
  17.                 break;  
  18.         }  
  19.         return !flag;  
  20.     }  
  1. /** 
  2.  *MyRelativeLayout的onTouchEvent打印结果 
  3.  */  
  4. D/MyRelativeLayout: onInterceptTouchEvent: ACTION_DOWN false  
  5. D/MyLinearlayout: onInterceptTouchEvent: ACTION_DOWN false  
  6. D/MyImageView: onTouchEvent: ACTION_DOWN true  
  7. D/MyImageView: dispatchTouchEvent: ACTION_DOWN true  
  8. D/MyLinearlayout: dispatchTouchEvent: ACTION_DOWN true  
  9. D/MyRelativeLayout: dispatchTouchEvent: ACTION_DOWN true  
  10.   
  11. D/MyRelativeLayout: onInterceptTouchEvent: ACTION_MOVE true  
  12. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE true  
  13. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  14. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE true  
  15. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  16. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE true  
  17. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  
  18. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE true  
  19.   
  20. D/MyRelativeLayout: onTouchEvent: ACTION_UP false  
  21. D/MyRelativeLayout: dispatchTouchEvent: ACTION_UP true  

看到onTouchEvent响应了ACTION_MOVE、ACTION_UP事件,证明第一层意识是正确。

接下来证明第二层:当前MyRelativeLayout的onTouchEvent返回true后,将无法在onInterceptTouchEvent()方法中接收ACTION_DOWN之外的事件。

PS:从上面的打印结果,无法得出该结论,其中onInterceptTouchEvent打印了一句:ACTION_MOVE

推荐阅读

Android事件分发流程分析证明(2)

当前文章价值9.64元,扫一扫支付后添加微信提供帮助!(如不能解决您的问题,可以申请退款)

你可能感兴趣的文章

来源:每日教程每日一例,深入学习实用技术教程,关注公众号TeachCourse
转载请注明出处: https://www.teachcourse.cn/2108.html ,谢谢支持!

资源分享

Android组件ViewPager+View实现滑动切换示例 Android组件ViewPager+View实
如何给WordPress长文章添加分页功能 如何给WordPress长文章添加分页
Python框架Flask封装和SQLAlchemy实际应用 Python框架Flask封装和SQLA
Android开发之深入理解Android 7.0系统权限更改相关文档 Android开发之深入理解Android

发表评论

呲牙 憨笑 坏笑 偷笑 色 微笑 抓狂 睡觉 酷 流汗 鼓掌 大哭 可怜 疑问 晕 惊讶 得意 尴尬 发怒 奋斗 衰 骷髅 啤酒 吃饭 礼物 强 弱 握手 OK NO 勾引 拳头 差劲 爱你

表情