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

2016-11-24 21:29 阅读 3,507 次 评论 0 条
版权声明:本文著作权归TeachCourse所有,未经许可禁止转载,谢谢支持!
转载请注明出处:http://teachcourse.cn/2113.html

摘要:

上一篇文章分析事件传递和事件处理的顺序,从运行Demo的角度说明onTouchEvent、dispatchTouchEvent方法和onInterceptTouchEvent方法的使用,重点理解每个方法返回值得含义。这一篇文章继续介绍如何控制拦截事件的返回值解决手势冲突的问题,对比说明requestDisallowInterceptTouchEvent和onInterceptTouchEvent的使用,进一步熟悉事件分发机制的原理。如果没有看过上一篇文章的,可以先了解一下《Android事件分发流程分析证明(1)》。

001-dispatchtouchevent

实验四:证明requestDisallowInterceptTouchEvent可以拦截事件

在MyImageView的onTouchEvent的回调方法中,我们调用MyRelativeLayout的requestDisallowInterceptTouchEvent(boolean disallowIntercept),决定是否禁用父容器的onInterceptTouchEvent方法。

PS:true表示禁用onInterceptTouchEvent;否则反之

  1. case MotionEvent.ACTION_DOWN:  
  2.      if (mParentView!=null)  
  3.          mParentView.requestDisallowInterceptTouchEvent(true);  
  4.      Log.d(TAG, "onTouchEvent: ACTION_MOVE " + flag);  
  5. break;  
  1. /** 
  2.  *指定父容器名称 
  3.  */  
  4. private ViewGroup  mParentView;  
  5.   
  6. public void setmParentView(ViewGroup mParentView) {  
  7.         this.mParentView = mParentView;  
  8. }  

查看log打印结果

  1. D/MyRelativeLayout: onInterceptTouchEvent: ACTION_DOWN false  
  2. D/MyLinearlayout: onInterceptTouchEvent: ACTION_DOWN false  
  3. D/MyRelativeLayout: requestDisallowInterceptTouchEvent: true  
  4. D/MyImageView: requestDisallowInterceptTouchEvent: true  
  5. D/MyImageView: onTouchEvent: ACTION_DOWN true  
  6. D/MyImageView: dispatchTouchEvent: ACTION_DOWN true  
  7. D/MyLinearlayout: dispatchTouchEvent: ACTION_DOWN true  
  8. D/MyRelativeLayout: dispatchTouchEvent: ACTION_DOWN true  
  9. D/MyLinearlayout: onInterceptTouchEvent: ACTION_MOVE false  
  10. D/MyRelativeLayout: requestDisallowInterceptTouchEvent: true  

-------------------------分析-----------------------------

  1. D/MyImageView: requestDisallowInterceptTouchEvent: true  
  2. D/MyImageView: onTouchEvent: ACTION_MOVE true  

上述两句log的含义,在onTouchEvent回调方法ACTION_MOVE状态,禁用MyRelativeLayout的onInterceptTouchEvent回调方法;onTouchEvent返回true,表示当期MyImageView响应并消耗事件

  1. D/MyImageView: dispatchTouchEvent: ACTION_MOVE true  
  2. D/MyLinearlayout: dispatchTouchEvent: ACTION_MOVE true  
  3. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE true  

上面三句log的含义,回调MyImageView、MyLinearLayout的dispatchTouchEvent方法,返回true,表示当前view需要快速处理事件

  1. D/MyLinearlayout: onInterceptTouchEvent: ACTION_MOVE false  

上面这句log的含义,MyLinearLayout在ACTION_MOVE状态下是否拦截事件,返回false,表示没有拦截事件

  1. D/MyRelativeLayout: requestDisallowInterceptTouchEvent: true  

父容器回调requestDisallowInterceptTouchEvent,返回true,禁用onInterceptTouchEvent回调方法

-------------------------重复-----------------------------

  1. D/MyImageView: requestDisallowInterceptTouchEvent: true  
  2. D/MyImageView: onTouchEvent: ACTION_MOVE true  
  3. D/MyImageView: dispatchTouchEvent: ACTION_MOVE true  
  4. D/MyLinearlayout: dispatchTouchEvent: ACTION_MOVE true  
  5. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE true  
  6. D/MyLinearlayout: onInterceptTouchEvent: ACTION_MOVE false  

-------------------------重复-----------------------------

  1. D/MyRelativeLayout: requestDisallowInterceptTouchEvent: true  
  2. D/MyImageView: requestDisallowInterceptTouchEvent: true  
  3. D/MyImageView: onTouchEvent: ACTION_MOVE true  
  4. D/MyImageView: dispatchTouchEvent: ACTION_MOVE true  
  5. D/MyLinearlayout: dispatchTouchEvent: ACTION_MOVE true  
  6. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE true  
  7. D/MyLinearlayout: onInterceptTouchEvent: ACTION_MOVE false  
  8. D/MyRelativeLayout: requestDisallowInterceptTouchEvent: true  

-------------------------重复-----------------------------

  1. D/MyImageView: requestDisallowInterceptTouchEvent: true  
  2. D/MyImageView: onTouchEvent: ACTION_MOVE true  
  3. D/MyImageView: dispatchTouchEvent: ACTION_MOVE true  
  4. D/MyLinearlayout: dispatchTouchEvent: ACTION_MOVE true  
  5. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE true  
  6. D/MyLinearlayout: onInterceptTouchEvent: ACTION_MOVE false  
  7. D/MyRelativeLayout: requestDisallowInterceptTouchEvent: true  

-------------------------重复-----------------------------

  1. D/MyImageView: requestDisallowInterceptTouchEvent: true  
  2. D/MyImageView: onTouchEvent: ACTION_MOVE true  
  3. D/MyImageView: dispatchTouchEvent: ACTION_MOVE true  
  4. D/MyLinearlayout: dispatchTouchEvent: ACTION_MOVE true  
  5. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE true  
  6. D/MyLinearlayout: onInterceptTouchEvent: ACTION_MOVE false  
  7. D/MyRelativeLayout: requestDisallowInterceptTouchEvent: true  

-------------------------重复-----------------------------

  1. D/MyImageView: requestDisallowInterceptTouchEvent: true  
  2. D/MyImageView: onTouchEvent: ACTION_MOVE true  
  3. D/MyImageView: dispatchTouchEvent: ACTION_MOVE true  
  4. D/MyLinearlayout: dispatchTouchEvent: ACTION_MOVE true  
  5. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE true  
  6. D/MyLinearlayout: onInterceptTouchEvent: ACTION_MOVE false  
  7. D/MyRelativeLayout: requestDisallowInterceptTouchEvent: true  

-------------------------重复-----------------------------

  1. D/MyImageView: requestDisallowInterceptTouchEvent: true  
  2. D/MyImageView: onTouchEvent: ACTION_MOVE true  
  3. D/MyImageView: dispatchTouchEvent: ACTION_MOVE true  
  4. D/MyLinearlayout: dispatchTouchEvent: ACTION_MOVE true  
  5. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE true  
  6. D/MyLinearlayout: onInterceptTouchEvent: ACTION_MOVE false  
  7. D/MyRelativeLayout: requestDisallowInterceptTouchEvent: true  

-------------------------ACTION_UP-----------------------------

  1. D/MyImageView: requestDisallowInterceptTouchEvent: true  
  2. D/MyImageView: onTouchEvent: ACTION_UP true  
  3. D/MyImageView: dispatchTouchEvent: ACTION_UP true  
  4. D/MyLinearlayout: dispatchTouchEvent: ACTION_UP true  
  5. D/MyRelativeLayout: dispatchTouchEvent: ACTION_UP true  
  6. D/EventDispatchActivity: onClick: dispatch_event_iv  

结论:子控件调用父容器的requestDisallowInterceptTouchEvent()方法禁用了父容器的onInterceptTouchEvent()方法。

实验五:如何根据ACTION的状态拦截事件?

简单的理解就是在一个View视图的层次结构中,怎么让ViewPager可以左右滑动,怎么让ListView可以上下滑动,在左右滑动的时候即ACTION_MOVE状态拦截事件,其它状态(ACTION_DOWN和ACTION_UP)恢复事件传递。

为了模拟上述的实验,这里以MyButton为对象,在ACTION_DOWN和ACTION_UP时调用requestDisallowInterceptTouchEvent,设置为false,只在ACTION_MOVE设置为true,重写onTouchEvent的代入如下:

  1. case MotionEvent.ACTION_DOWN:  
  2.     if (mParentView != null) {  
  3.         mParentView.requestDisallowInterceptTouchEvent(false);  
  4.         Log.d(TAG, "requestDisallowInterceptTouchEvent: "+false);  
  5.     }  
  6.     Log.d(TAG, "onTouchEvent: ACTION_DOWN " + flag);  
  7.     break;  
  8.     case MotionEvent.ACTION_MOVE:  
  9.     if (mParentView != null){  
  10.         mParentView.requestDisallowInterceptTouchEvent(true);  
  11.         Log.d(TAG, "requestDisallowInterceptTouchEvent: "+true);  
  12.     }  
  13.     Log.d(TAG, "onTouchEvent: ACTION_MOVE " + flag);  
  14.     break;  
  15.     case MotionEvent.ACTION_UP:  
  16.     if (mParentView != null) {  
  17.         mParentView.requestDisallowInterceptTouchEvent(false);  
  18.         Log.d(TAG, "requestDisallowInterceptTouchEvent: "+false);  
  19.     }  
  20.     Log.d(TAG, "onTouchEvent: ACTION_UP " + flag);  
  21.     break;  

在MyButton上滑动屏幕,查看log打印结果:

  1. D/MyRelativeLayout: onInterceptTouchEvent: ACTION_DOWN false  
  2. D/MyLinearlayout: onInterceptTouchEvent: ACTION_DOWN false  
  3. D/MyRelativeLayout: requestDisallowInterceptTouchEvent: false  
  4. D/MyButton: requestDisallowInterceptTouchEvent: false  
  5. D/MyButton: onTouchEvent: ACTION_DOWN true  
  6. D/MyButton: dispatchTouchEvent: ACTION_DOWN true  

MyButton没有打印出ACTION_MOVE的状态,即没有禁用父容器的onInterceptTouchEvent回调方法。

  1. D/MyLinearlayout: dispatchTouchEvent: ACTION_DOWN true  
  2. D/MyRelativeLayout: dispatchTouchEvent: ACTION_DOWN true  

上面两句log的含义,MyLinearLayout和MyRelativeLayout在ACTION_DOWN时返回true,对事件进行快速处理。

  1. D/MyRelativeLayout: onInterceptTouchEvent: ACTION_MOVE true  

滑动屏幕时onInterceptTouchEvent返回true,拦截了事件继续传递。

  1. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE true  

滑动屏幕dispatchTouchEvent返回true,当前控件不再处理事件

  1. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  

滑动屏幕时onTouchEvent返回false,表示事件没有被消耗

-------------------------重复-----------------------------

  1. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  2. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  

-------------------------重复-----------------------------

  1. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  2. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  

-------------------------重复-----------------------------

  1. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  
  2. D/MyRelativeLayout: onTouchEvent: ACTION_MOVE false  

-------------------------重复-----------------------------

  1. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE false  

-------------------------ACTION_UP-----------------------------

  1. D/MyRelativeLayout: onTouchEvent: ACTION_UP false  
  2. D/MyRelativeLayout: dispatchTouchEvent: ACTION_UP false  

PS:为什么MyButton滑动屏幕时没有打印ACTION_MOVE的信息呢?

仔细观察MyRelativeLayout的onInterceptTouchEvent回调方法,在滑动屏幕的时候返回true,即拦截滑动事件传递。

实验六:如何让MyButton响应屏幕滑动事件?

从上面的实验看出是因为MyRelativeLayout拦截了事件,那么我们尝试禁用onInterceptTouchEvent拦截,重新运行项目。

  1. case MotionEvent.ACTION_DOWN:  
  2.     if (mParentView != null) {  
  3.         mParentView.requestDisallowInterceptTouchEvent(true);  
  4.         Log.d(TAG, "requestDisallowInterceptTouchEvent: "+true);  
  5.     }  
  6.     Log.d(TAG, "onTouchEvent: ACTION_DOWN " + flag);  
  7.    break;  

在MyButton触摸屏幕(ACTION_DOWN)时,调用父容器的方法禁用拦截,查看log打印结果:

  1. D/MyRelativeLayout: onInterceptTouchEvent: ACTION_DOWN false  
  2. D/MyLinearlayout: onInterceptTouchEvent: ACTION_DOWN false  
  3. D/MyRelativeLayout: requestDisallowInterceptTouchEvent: true  

上面这句log提示,我们禁用了父容器的拦截事件的方法,返回true

  1. D/MyButton: requestDisallowInterceptTouchEvent: true  
  2. D/MyButton: onTouchEvent: ACTION_DOWN true  

上面两句log显示,在我们调用父容器的requestDisallowInterceptTouchEvent方法前,先打印MyRelativeLayout被禁用拦截的log,禁用拦截发生在ACTION_DOWN状态。

  1. D/MyButton: dispatchTouchEvent: ACTION_DOWN true  
  2. D/MyLinearlayout: dispatchTouchEvent: ACTION_DOWN true  
  3. D/MyRelativeLayout: dispatchTouchEvent: ACTION_DOWN true  
  4. D/MyLinearlayout: onInterceptTouchEvent: ACTION_MOVE false  
  5. D/MyRelativeLayout: requestDisallowInterceptTouchEvent: true  
  6. D/MyButton: requestDisallowInterceptTouchEvent: true  
  7.   
  8. D/MyButton: onTouchEvent: ACTION_MOVE true  

从上面一句log看出,MyButton响应滑动屏幕的事件,证明事件拦截成功。

  1. D/MyButton: dispatchTouchEvent: ACTION_MOVE true  
  2. D/MyLinearlayout: dispatchTouchEvent: ACTION_MOVE true  
  3. D/MyRelativeLayout: dispatchTouchEvent: ACTION_MOVE true  
  4. D/MyLinearlayout: onInterceptTouchEvent: ACTION_UP false  
  5. D/MyRelativeLayout: requestDisallowInterceptTouchEvent: false  
  6. D/MyButton: requestDisallowInterceptTouchEvent: false  
  7.   
  8. D/MyButton: onTouchEvent: ACTION_UP true  
  9. D/MyButton: dispatchTouchEvent: ACTION_UP true  
  10. D/MyLinearlayout: dispatchTouchEvent: ACTION_UP true  
  11. D/MyRelativeLayout: dispatchTouchEvent: ACTION_UP true  

推荐阅读

Android事件分发流程测试运用(1)

关注公众号 扫一扫二维码,加我QQ

如果文章对你有帮助,欢迎点击上方按钮关注作者

来源:TeachCourse每周一次,深入学习Android教程,关注(QQ1589359239或公众号TeachCourse)
转载请注明出处:http://teachcourse.cn/2113.html
浅谈Menu、MenuItem和SubMenu 浅谈Menu、MenuItem和SubMe
面向抽象的编程思想之重写RecyclerView 面向抽象的编程思想之重写Recyc
Andorid开发之反编译工具apktool学习 Andorid开发之反编译工具apktoo
微信支付不成功的几个原因 微信支付不成功的几个原因

发表评论

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

表情