Android事件分发流程测试运用

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

摘要:

上两篇文章分析事件分析流程,这篇文章以及接下来的另一外一篇文章运用这些测试的结果,解决手势冲突的问题。

手势冲突实例一

水平方向的手势和垂直方向的手势冲突解决办法,参考了网上比较多的做法判断移动距离,比较deltaX和deltaY的大小,如果水平方向移动的距离大,判断为水平滑动,否则反之。现在准备了一个例子,ListView里面嵌套ViewPager,ViewPager是左右滑动,ListView是上下滑动,在ListView滑动的时候,调用onInterceptTouchEvent()方法拦截事件,从第一篇《Android事件分发流程分析证明(1)》介绍第一种拦截的方式,即onInterceptTouchEvent返回true

运行Demo的效果:

001-deltax-deltay

1、重写MyListView的onInterceptTouchEvent方法,然后返回true,在第一篇分析文章的实验三,可以推测,此时事件无法继续传递,MyListView的onTouchEvent响应事件,打印出deltaX和deltaY的值

  1. // 分别记录上次滑动的坐标  
  2. private double mLastX = 0;  
  3. private double mLastY = 0;  
  4. @Override  
  5. public boolean onTouchEvent(MotionEvent ev) {  
  6.         boolean flag = super.onTouchEvent(ev);  
  7.         double x = (int) ev.getX();  
  8.         double y = (int) ev.getY();  
  9.   
  10.         switch (ev.getAction()) {  
  11.             case MotionEvent.ACTION_DOWN:  
  12.                 mLastX = x;  
  13.                 mLastY = y;  
  14.   
  15.                 Log.d(TAG, "onTouchEvent: ACTION_DOWN " + flag);  
  16.                 break;  
  17.             case MotionEvent.ACTION_MOVE:  
  18.                 double deltaX = x - mLastX;  
  19.                 double deltaY = y - mLastY;  
  20.                 if (Math.abs(deltaY) > Math.abs(deltaX)) {  
  21.   
  22.                 }  
  23.                 Log.d(TAG, "onTouchEvent: ACTION_MOVE " + flag + "\ndeltaX=" + deltaX + "\ndeltaY" + deltaY);  
  24.                 break;  
  25.             case MotionEvent.ACTION_UP:  
  26.               
  27.                 Log.d(TAG, "onTouchEvent: ACTION_UP " + flag);  
  28.                 break;  
  29.         }  
  30.   
  31.         return flag;  
  32. }  

查看打印log的结果

  1. D/MyListView: onInterceptTouchEvent: ACTION_DOWN true  

这句log说明如果返回true,MyListView将无法接收后面的任何一个事件(ACTION_MOVE或ACTION_UP);target view将会接收到相同的事件,只不过伴随着ACTION_CANCEL事件,接下来的所有事件将会被传递到onTouchEvent()方法,不会再出现在这里。

  1. D/MyListView: onTouchEvent: ACTION_DOWN true  
  2. D/MyListView: onTouchEvent: ACTION_MOVE true  
  3.               deltaX=0.0  
  4.               deltaY-3.0  
  5. D/MyListView: onTouchEvent: ACTION_MOVE true  
  6.               deltaX=1.0  
  7.               deltaY-7.0  
  8. D/MyListView: onTouchEvent: ACTION_MOVE true  
  9.               deltaX=1.0  
  10.               deltaY-9.0  
  11. D/MyListView: onTouchEvent: ACTION_MOVE true  
  12.               deltaX=3.0  
  13.               deltaY-13.0  
  14. D/MyListView: onTouchEvent: ACTION_MOVE true  
  15.               deltaX=3.0  
  16.               deltaY-15.0  
  17. D/MyListView: onTouchEvent: ACTION_MOVE true  
  18.               deltaX=5.0  
  19.               deltaY-20.0  
  20. D/MyListView: onTouchEvent: ACTION_MOVE true  
  21.               deltaX=7.0  
  22.               deltaY-22.0  
  23. D/MyListView: onTouchEvent: ACTION_MOVE true  
  24.               deltaX=9.0  
  25.               deltaY-25.0  
  26. D/MyListView: onTouchEvent: ACTION_MOVE true  
  27.               deltaX=9.0  
  28.               deltaY-27.0  
  29. D/MyListView: onTouchEvent: ACTION_MOVE true  
  30.               deltaX=11.0  
  31.               deltaY-31.0  
  32. D/MyListView: onTouchEvent: ACTION_MOVE true  
  33.               deltaX=11.0  
  34.               deltaY-33.0  
  35. D/MyListView: onTouchEvent: ACTION_MOVE true  
  36.               deltaX=13.0  
  37.               deltaY-36.0  
  38. D/MyListView: onTouchEvent: ACTION_MOVE true  
  39.               deltaX=13.0  
  40.               deltaY-38.0  
  41. D/MyListView: onTouchEvent: ACTION_MOVE true  
  42.               deltaX=15.0  
  43.               deltaY-39.0  
  44. D/MyListView: onTouchEvent: ACTION_MOVE true  
  45.               deltaX=16.0  
  46.               deltaY-45.0  
  47. D/MyListView: onTouchEvent: ACTION_MOVE true  
  48.               deltaX=19.0  
  49.               deltaY-51.0  
  50. D/MyListView: onTouchEvent: ACTION_MOVE true  
  51.               deltaX=18.0  
  52.               deltaY-54.0  
  53. D/MyListView: onTouchEvent: ACTION_MOVE true  
  54.               deltaX=20.0  
  55.               deltaY-56.0  
  56. D/MyListView: onTouchEvent: ACTION_UP true  

可以看到onTouchEvent响应事件的按下状态、滑动状态和弹起状态。

但是这个时候的ViewPager处于视图层次结构的下一级,即MyListView的内部,在onInterceptTouchEvent的ACTION_DOWN状态就拦截了事件,在其内部的所有控件将无法滑动,这个时候的ViewPager是无法滑动的。

想要让ViewPager滑动,我们需要修改onIntercetTouchEvent()的逻辑,不再是按下状态就拦截,而是在滑动状态的时候,判断deltaX和deltaY的大小,deltaX大于deltaY,onInterceptTouchEvent返回false,否则反之。

  1. // 分别记录上次滑动的坐标(onInterceptTouchEvent)  
  2. private int mLastXIntercept = 0;  
  3. private int mLastYIntercept = 0;  
  4.   
  5. @Override  
  6.     public boolean onInterceptTouchEvent(MotionEvent ev) {  
  7.         boolean flag = super.onInterceptTouchEvent(ev);  
  8.         double x = (int) ev.getX();  
  9.         double y = (int) ev.getY();  
  10.         switch (ev.getAction()) {  
  11.             case MotionEvent.ACTION_DOWN:  
  12.                 mLastXIntercept = x;  
  13.                 mLastYIntercept = y;  
  14.                 flag=false;  
  15.                 Log.d(TAG, "onInterceptTouchEvent: ACTION_DOWN " + flag);  
  16.                 break;  
  17.             case MotionEvent.ACTION_MOVE:  
  18.                 double deltaX = x - mLastXIntercept;  
  19.                 double deltaY = y - mLastYIntercept;  
  20.                 if (Math.abs(deltaY) > Math.abs(deltaX)) {  
  21.                     flag = true;  
  22.                 }  
  23.                 Log.d(TAG, "onInterceptTouchEvent: ACTION_MOVE " + flag + "\ndeltaX=" + deltaX + "\ndeltaY" + deltaY);  
  24.                 break;  
  25.             case MotionEvent.ACTION_UP:  
  26.                 flag=false;  
  27.                 Log.d(TAG, "onInterceptTouchEvent: ACTION_UP " + flag);  
  28.                 break;  
  29.         }  
  30.         return flag;  
  31.     }  

查看打印log的结果:

  1. D/MyListView: onInterceptTouchEvent: ACTION_DOWN false  

上面这句log返回false,那么接下来的每一个事件都将会首先传递到这里,然后再传递到target的onTouchEvent()方法,所以可以判断此时的ViewPager的onTouchEvent将会响应滑动的手势。

  1. D/MyListView: onTouchEvent: ACTION_DOWN true  
  2. D/MyListView: onTouchEvent: ACTION_MOVE true  
  3.               deltaX=0.0  
  4.               deltaY=-8.0  
  5. D/MyListView: onTouchEvent: ACTION_MOVE true  
  6.               deltaX=0.0  
  7.               deltaY=-13.0  
  8. D/MyListView: onTouchEvent: ACTION_MOVE true  
  9.               deltaX=-2.0  
  10.               deltaY=-23.0  
  11. D/MyListView: onTouchEvent: ACTION_MOVE true  
  12.               deltaX=-2.0  
  13.               deltaY=-28.0  
  14. D/MyListView: onTouchEvent: ACTION_MOVE true  
  15.               deltaX=-2.0  
  16.               deltaY=-34.0  
  17. D/MyListView: onTouchEvent: ACTION_MOVE true  
  18.               deltaX=-2.0  
  19.               deltaY=-35.0  
  20. D/MyListView: onTouchEvent: ACTION_MOVE true  
  21.               deltaX=-2.0  
  22.               deltaY=-45.0  
  23. D/MyListView: onTouchEvent: ACTION_MOVE true  
  24.               deltaX=-2.0  
  25.               deltaY=-54.0  
  26. D/MyListView: onTouchEvent: ACTION_MOVE true  
  27.               deltaX=1.0  
  28.               deltaY=-65.0  
  29. D/MyListView: onTouchEvent: ACTION_MOVE true  
  30.               deltaX=3.0  
  31.               deltaY=-67.0  
  32. D/MyListView: onTouchEvent: ACTION_MOVE true  
  33.               deltaX=4.0  
  34.               deltaY=-73.0  
  35. D/MyListView: onTouchEvent: ACTION_MOVE true  
  36.               deltaX=9.0  
  37.               deltaY=-86.0  
  38. D/MyListView: onTouchEvent: ACTION_MOVE true  
  39.               deltaX=12.0  
  40.               deltaY=-100.0  
  41. D/MyListView: onTouchEvent: ACTION_MOVE true  
  42.               deltaX=14.0  
  43.               deltaY=-102.0  
  44. D/MyListView: onTouchEvent: ACTION_MOVE true  
  45.               deltaX=17.0  
  46.               deltaY=-106.0  
  47. D/MyListView: onTouchEvent: ACTION_MOVE true  
  48.               deltaX=17.0  
  49.               deltaY=-110.0  
  50. D/MyListView: onTouchEvent: ACTION_MOVE true  
  51.               deltaX=18.0  
  52.               deltaY=-116.0  
  53. D/MyListView: onTouchEvent: ACTION_MOVE true  
  54.               deltaX=24.0  
  55.               deltaY=-121.0  
  56. D/MyListView: onTouchEvent: ACTION_MOVE true  
  57.               deltaX=26.0  
  58.               deltaY=-127.0  
  59. D/MyListView: onTouchEvent: ACTION_MOVE true  
  60.               deltaX=28.0  
  61.               deltaY=-131.0  
  62. D/MyListView: onTouchEvent: ACTION_MOVE true  
  63.               deltaX=30.0  
  64.               deltaY=-131.0  
  65. D/MyListView: onTouchEvent: ACTION_UP true  

这个时候的ViewPager可以左右滑动,同时ListView也可以上下滑动,ViewPager和ListView的手势冲突的问题基本解决。

为了查看ViewPager的onTouchEvent方法是否响应了滑动事件,我们再来重写ViewPager的onTouchEvent()方法

  1. D/MyListView: onInterceptTouchEvent: ACTION_DOWN false  
  2. D/MyViewPager: onTouchEvent: ACTION_DOWN true  
  3. D/MyListView: onInterceptTouchEvent: ACTION_MOVE false  
  4.               deltaX=-5.0  
  5.               deltaY=0.0  

在屏幕上滑动ViewPager,看到MyListView的onInterceptTouchEvent返回false,那是因为deltaX>deltaY(比较绝对值的大小),MyListView识别当前手势为左右滑动,通知MyListView不要拦截事件。

  1. D/MyViewPager: onTouchEvent: ACTION_MOVE true  
  2.                deltaX=-5.0  
  3.                deltaY=0.0  
  4. D/MyListView: onInterceptTouchEvent: ACTION_MOVE false  
  5.               deltaX=-17.0  
  6.               deltaY=3.0  
  7. D/MyViewPager: onTouchEvent: ACTION_MOVE true  
  8.                deltaX=-17.0  
  9.                deltaY=3.0  
  10. D/MyListView: onInterceptTouchEvent: ACTION_MOVE false  
  11.               deltaX=-34.0  
  12.               deltaY=6.0  
  13. D/MyViewPager: onTouchEvent: ACTION_MOVE true  
  14.                deltaX=-34.0  
  15.                deltaY=6.0  
  16. D/MyViewPager: onTouchEvent: ACTION_MOVE true  
  17.                deltaX=-60.0  
  18.                deltaY=8.0  
  19. D/MyViewPager: onTouchEvent: ACTION_MOVE true  
  20.                deltaX=-83.0  
  21.                deltaY=13.0  
  22. D/MyViewPager: onTouchEvent: ACTION_MOVE true  
  23.                deltaX=-95.0  
  24.                deltaY=15.0  
  25. D/MyViewPager: onTouchEvent: ACTION_MOVE true  
  26.                deltaX=-129.0  
  27.                deltaY=21.0  
  28. D/MyViewPager: onTouchEvent: ACTION_MOVE true  
  29.                deltaX=-157.0  
  30.                deltaY=26.0  
  31. D/MyViewPager: onTouchEvent: ACTION_MOVE true  
  32.                deltaX=-181.0  
  33.                deltaY=31.0  
  34. D/MyViewPager: onTouchEvent: ACTION_MOVE true  
  35.                deltaX=-191.0  
  36.                deltaY=31.0  
  37. D/MyViewPager: onTouchEvent: ACTION_MOVE true  
  38.                deltaX=-221.0  
  39.                deltaY=35.0  
  40. D/MyViewPager: onTouchEvent: ACTION_MOVE true  
  41.                deltaX=-243.0  
  42.                deltaY=37.0  
  43. D/MyViewPager: onTouchEvent: ACTION_MOVE true  
  44.                deltaX=-281.0  
  45.                deltaY=41.0  
  46. D/MyViewPager: onTouchEvent: ACTION_MOVE true  
  47.                deltaX=-310.0  
  48.                deltaY=41.0  
  49. D/MyViewPager: onTouchEvent: ACTION_MOVE true  
  50.                deltaX=-346.0  
  51.                deltaY=37.0  
  52. D/MyViewPager: onTouchEvent: ACTION_MOVE true  
  53.                deltaX=-372.0  
  54.                deltaY=33.0  
  55. D/MyViewPager: onTouchEvent: ACTION_UP true  

可以看到在ViewPager每次滑动后,MyListView都会进行一次识别,当前deltaX和deltaY之间的关系,可以猜想,如果deltaY>deltaX,那么MyListView的onInterceptTouchEvent肯定返回true,然后不再打印出来ViewPager的log信息,最后将可以执行上下滑动的操作。

在ViewPager的位置,上下滑动,查看打印log的结果:

  1. D/MyListView: onInterceptTouchEvent: ACTION_DOWN false  
  2. D/MyViewPager: onTouchEvent: ACTION_DOWN true  
  3. D/MyListView: onInterceptTouchEvent: ACTION_MOVE true  
  4.               deltaX=0.0  
  5.               deltaY=-2.0  
  6. D/MyListView: onTouchEvent: ACTION_MOVE true  
  7.               deltaX=441.0  
  8.               deltaY=331.0  
  9. D/MyListView: onTouchEvent: ACTION_MOVE true  
  10.               deltaX=441.0  
  11.               deltaY=330.0  
  12. D/MyListView: onTouchEvent: ACTION_MOVE true  
  13.               deltaX=441.0  
  14.               deltaY=326.0  
  15. D/MyListView: onTouchEvent: ACTION_MOVE true  
  16.               deltaX=441.0  
  17.               deltaY=324.0  
  18. D/MyListView: onTouchEvent: ACTION_MOVE true  
  19.               deltaX=441.0  
  20.               deltaY=321.0  
  21. D/MyListView: onTouchEvent: ACTION_MOVE true  
  22.               deltaX=441.0  
  23.               deltaY=318.0  
  24. D/MyListView: onTouchEvent: ACTION_MOVE true  
  25.               deltaX=441.0  
  26.               deltaY=317.0  
  27. D/MyListView: onTouchEvent: ACTION_MOVE true  
  28.               deltaX=441.0  
  29.               deltaY=314.0  
  30. D/MyListView: onTouchEvent: ACTION_MOVE true  
  31.               deltaX=443.0  
  32.               deltaY=309.0  
  33. D/MyListView: onTouchEvent: ACTION_MOVE true  
  34.               deltaX=443.0  
  35.               deltaY=302.0  
  36. D/MyListView: onTouchEvent: ACTION_MOVE true  
  37.               deltaX=443.0  
  38.               deltaY=302.0  
  39. D/MyListView: onTouchEvent: ACTION_MOVE true  
  40.               deltaX=443.0  
  41.               deltaY=300.0  
  42. D/MyListView: onTouchEvent: ACTION_MOVE true  
  43.               deltaX=443.0  
  44.               deltaY=295.0  
  45. D/MyListView: onTouchEvent: ACTION_UP true  

上面的log没有打印MyViewPager的log信息,同时MyListView的onInterceptTouchEvent返回true,证明我们的猜想是正确的,算是完全明白了比较deltaX和deltaY的手势冲突解决办法了,是不是有点小激动呀 <^ _ ^> 。

PS:>在使用的时候,感觉上述这种方式,还是不怎么满意,滑动ViewPager的时候感觉还是有点卡顿,本想要左右滑动的,但稍微水平滑动倾斜了一点,就成了垂直滑动了,造成了误识。

在下面的一篇文章中,我们将通过滑动的倾斜角度,识别事件的拦截,拦截的思路和比较移动距离是一样的,这里通过比较倾斜的角度,只需要将if语句的条件改一下即可

  1. case MotionEvent.ACTION_MOVE:  
  2.                 double deltaX =x- mLastX;  
  3.                 double deltaY =y- mLastY;  
  4.                 double degrees=calculateDegrees(deltaX,deltaY);  
  5.         /** 
  6.          *注释掉deltaX和deltaY 
  7.          */  
  8.                 if (isSuitable(degrees)){  
  9. //                if (Math.abs(deltaY) > Math.abs(deltaX)) {  
  10.                    flag=true;  
  11.                 }  
  12.                 Log.d(TAG, "dispatchTouchEvent: ACTION_MOVE " + flag);  
  13.   break;  
  1. /**  
  2.     * 判断是否合适的角度  
  3.     * @return  
  4.     */    
  5.    private boolean isSuitable(double degrees) {    
  6.        if (degrees>45&&degrees<135|degrees>225&&degrees<315)    
  7.            return true;    
  8.     
  9.        return false;    
  10.     
  11.    }     
  12.     
  13.    /**  
  14.     * 根据反正切计算弧度,再由弧度计算角度  
  15.     * @param deltaX  
  16.     * @param deltaY  
  17.     * @return  
  18.     */    
  19.    private double calculateDegrees(double deltaX, double deltaY) {    
  20.   
  21.        deltaX=Math.abs(deltaX);    
  22.        deltaY=Math.abs(deltaY);    
  23.   
  24.        return Math.toDegrees(Math.atan(deltaY/deltaX));     
  25.    }    

由于篇幅比较长,将在下一篇文章详细说明如何计算倾斜的角度,通过滑动的角度拦截事件。

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

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

来源:TeachCourse每周一次,深入学习Android教程,关注(QQ1589359239或公众号TeachCourse)
转载请注明出处:http://teachcourse.cn/2118.html
分类:Android 标签:, ,
WebView加载HTML5百度地图空白问题 WebView加载HTML5百度地图
关于Android app的launcher图标更换后,仍然显示默认的ic_launcher图标的解决方法 关于Android app的launcher图标
你或许理解错了Android系统权限管理的这两个概念 你或许理解错了Android系统权限
关于如何解决“NoClassDefFoundError”错误的问题? 关于如何解决“NoClassDefFo

发表评论

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

表情