菜鸟进阶之Android Touch事件传递(二)

这是touch事件传递系列博客的第二篇,如果想了解touch和click的那些事,请浏览投产事件传递系列的第一篇。http://blog.csdn.net/bingospunky/article/details/43603397

理理思路,我发现touch传递这部分的内容很多,所以每篇博客介绍一个方面比较好。这篇博客主要介绍touch事件传递的现象,一个简单的demo,让大家可以看到touch一步一步传递的过程。下篇博客中在研究源码是怎么实现的。再后面的博客会试图改变这篇文章看到的touch的传递过程,比如viewpager里嵌套listview。

demo

代码A:

[java] view
plain
copyprint?

  1. public class LayoutView1 extends  {
  2. private final String TAG = "qingtian";
  3. public LayoutView1(Context context, AttributeSet attrs) {
  4. super(context, attrs);
  5. }
  6. public boolean onInterceptTouchEvent(MotionEvent ev) {
  7. int action = ev.getAction();
  8. switch (action) {
  9. case MotionEvent.ACTION_DOWN:
  10. Log.d(TAG, "LayoutView1  Intercept  DOWN");
  11. break;
  12. case MotionEvent.ACTION_MOVE:
  13. Log.d(TAG, "LayoutView1  Intercept  MOVE");
  14. break;
  15. case MotionEvent.ACTION_UP:
  16. Log.d(TAG, "LayoutView1  Intercept  UP");
  17. break;
  18. case MotionEvent.ACTION_CANCEL:
  19. Log.d(TAG, "LayoutView1  Intercept  CANCEL");
  20. break;
  21. }
  22. return false;
  23. }
  24. @SuppressLint("ClickableViewAccessibility")
  25. public boolean onTouchEvent(MotionEvent ev) {
  26. int action = ev.getAction();
  27. switch (action) {
  28. case MotionEvent.ACTION_DOWN:
  29. Log.d(TAG, "LayoutView1  Touch  DOWN");
  30. break;
  31. case MotionEvent.ACTION_MOVE:
  32. Log.d(TAG, "LayoutView1  Touch  MOVE");
  33. break;
  34. case MotionEvent.ACTION_UP:
  35. Log.d(TAG, "LayoutView1  Touch  UP");
  36. break;
  37. case MotionEvent.ACTION_CANCEL:
  38. Log.d(TAG, "LayoutView1  Touch  CANCEL");
  39. break;
  40. }
  41. }
  42. @Override
  43. public boolean dispatchTouchEvent(MotionEvent ev) {
  44. Log.d(TAG, "LayoutView1  dispatch   " );
  45. boolean r = super.dispatchTouchEvent(ev);
  46. Log.d(TAG, "LayoutView1  dispatch 结果   "+r);
  47. return r;
  48. }
  49. }

代码B:

[java] view
plain
copyprint?

  1. public class LayoutView2 extends LinearLayout {
  2. private final String TAG = "qingtian";
  3. public LayoutView2(Context context, AttributeSet attrs) {
  4. super(context, attrs);
  5. }
  6. public boolean onInterceptTouchEvent(MotionEvent ev) {
  7. int action = ev.getAction();
  8. switch (action) {
  9. case MotionEvent.ACTION_DOWN:
  10. Log.d(TAG, "LayoutView2  Intercept  DOWN");
  11. break;
  12. case MotionEvent.ACTION_MOVE:
  13. Log.d(TAG, "LayoutView2  Intercept  MOVE");
  14. break;
  15. case MotionEvent.ACTION_UP:
  16. Log.d(TAG, "LayoutView2  Intercept  UP");
  17. break;
  18. case MotionEvent.ACTION_CANCEL:
  19. Log.d(TAG, "LayoutView2  Intercept  CANCEL");
  20. break;
  21. }
  22. return false;
  23. }
  24. public boolean onTouchEvent(MotionEvent ev) {
  25. int action = ev.getAction();
  26. switch (action) {
  27. case MotionEvent.ACTION_DOWN:
  28. Log.d(TAG, "LayoutView2  Touch  DOWN");
  29. break;
  30. case MotionEvent.ACTION_MOVE:
  31. Log.d(TAG, "LayoutView2  Touch  MOVE");
  32. break;
  33. case MotionEvent.ACTION_UP:
  34. Log.d(TAG, "LayoutView2  Touch  UP");
  35. break;
  36. case MotionEvent.ACTION_CANCEL:
  37. Log.d(TAG, "LayoutView2  Touch  CANCEL");
  38. break;
  39. }
  40. return false;
  41. }
  42. @Override
  43. public boolean dispatchTouchEvent(MotionEvent ev) {
  44. Log.d(TAG, "LayoutView2  dispatch  ");
  45. boolean r = super.dispatchTouchEvent(ev);
  46. Log.d(TAG, "LayoutView2  dispatch  结果  "+r);
  47. return r;
  48. }
  49. }

代码C:

[java] view
plain
copyprint?

  1. public class MyTextView extends TextView {
  2. private final String TAG = "qingtian";
  3. public MyTextView(Context context, AttributeSet attrs) {
  4. super(context, attrs);
  5. }
  6. public boolean onTouchEvent(MotionEvent ev) {
  7. int action = ev.getAction();
  8. switch (action) {
  9. case MotionEvent.ACTION_DOWN:
  10. Log.d(TAG, "MyTextView  Touch   DOWN");
  11. break;
  12. case MotionEvent.ACTION_MOVE:
  13. Log.d(TAG, "MyTextView  Touch   MOVE");
  14. break;
  15. case MotionEvent.ACTION_UP:
  16. Log.d(TAG, "MyTextView  Touch   UP");
  17. break;
  18. case MotionEvent.ACTION_CANCEL:
  19. Log.d(TAG, "MyTextView  Touch   CANCEL");
  20. break;
  21. }
  22. return false;
  23. }
  24. @Override
  25. public boolean dispatchTouchEvent(MotionEvent ev) {
  26. Log.d(TAG, "MyTextView  dispatch  " );
  27. boolean r = super.dispatchTouchEvent(ev);
  28. Log.d(TAG, "MyTextView  dispatch   结果  "+r);
  29. return r;
  30. }
  31. //  public void onClick(View v) {
  32. //      Log.d(TAG, "onClick");
  33. //  }
  34. //
  35. //  public boolean onLongClick(View v) {
  36. //      Log.d(TAG, "onLongClick");
  37. //      return false;
  38. //  }
  39. }

布局文件D:

[html] view
plain
copyprint?

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <com.example.testontouch.LayoutView1 xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. android:orientation="vertical" >
  6. <com.example.testontouch.LayoutView2
  7. android:layout_width="fill_parent"
  8. android:layout_height="fill_parent"
  9. android:gravity="center"
  10. android:orientation="vertical" >
  11. <com.example.testontouch.MyTextView
  12. android:layout_width="200dp"
  13. android:layout_height="150dp"
  14. android:background="#FFFFFF"
  15. android:text="Hello World"
  16. android:textColor="#0000FF"
  17. android:textSize="40sp"
  18. android:textStyle="bold" />
  19. </com.example.testontouch.LayoutView2>
  20. </com.example.testontouch.LayoutView1>

你可以改变这三个方法的返回值,观察touch都会传递到哪里。

PS:网上有很多类似的demo,基本没有改变dispatchTouchEvent的返回值的(虽然实际开发中基本不会改变这个返回值),强烈建议修改这个方法的返回值,尤其对于:如果你了解touch传递的U形,改变这个值会改变U形,不是改变形,而是使U形变长或变短。

总结

Android官方文档上

onInterceptTouchEvent()与onTouchEvent()的机制:

1.down事件首先会传递到onInterceptTouchEvent()方法

2.如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之return false,那么后续的move, up等事件将继续会先传递给该ViewGroup,之后才和down事件一样传递给最终的目标view的onTouchEvent()处理

3.如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return true,那么后续的move, up等事件将不再传递给onInterceptTouchEvent(),而是和down事件一样传递给该ViewGroup的onTouchEvent()处理,注意,目标view将接收不到任何事件。

4.如果最终需要处理事件的view的onTouchEvent()返回了false,那么该事件将被传递至其上一层次的view的onTouchEvent()处理

5.如果最终需要处理事件的view 的onTouchEvent()返回了true,那么后续事件将可以继续传递给该view的onTouchEvent()处理。

我的理解

1.touch事件传递与dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent这三个方法相关,可以看到这三个方法都返回boolean类型的值,如果我们能了解这三个方法的返回值的含义,就在自定义组件的时候通过控制返回的值影响touch事件的传递,这是理解的第一个层次。如果能从源码里真正理解来这三个返回值是怎么被使用的,那么我们在自定义view的时候可以重写使用返回值的部分,那么我们就可以改变touch传递的U形,更深的理解touch,比如我一直想弄明白的一个问题:viewpager里嵌套listview,怎么实现区分viewpage响应滑动,还是listview响应滑动,这是我理解的更高的一个层次。当然第二层我还没有达到,写完这个系列的博客后应该可以达到。

2.这篇博客里只有viewgroup和view这两种组件,viewgroup又会存在嵌套的关系,所以你在理解事件传递的时候一定要用点递归的概念。

3.当一个touch事件到达一个viewgroup时,先到达dispatchTouchEvent这个方法,然后到onInterceptTouchEvent方法:

a、如果onInterceptTouchEvent返回true,那么执行该viewgroup的onTouchEvent。由该viewgroup处理touch,不再传递到child组件。viewgroup的onInterceptTouchEvent的返回值根据该viewgroup的onTouchEvent的返回值确定。

b、如果onInterceptTouchEvent返回false,那么寻找对应位置上的child:

b1、如果child存在,执行该child的dispatchTouchEvent:

b1一、如果child的dispatchTouchEvent返回true,表示child消化了该事件,viewgroup不做处理,viewgroup的onInterceptTouchEvent的返回值为true。

b1二、如果child的dispatchTouchEvent返回false,那么再执行viewgroup的onTouchEvent,viewgroup的onInterceptTouchEvent的返回值根据该viewgroup的onTouchEvent的返回值确定。

b2、如果child不存在,那么执行该viewgroup的onTouchEvent,viewgroup的onInterceptTouchEvent的返回值根据该viewgroup的onTouchEvent的返回值确定。

4.当一个touch事件到达一个view时,先到达dispatchTouchEvent这个方法,然后执行view的onTouchEvent方法。

5.这里忽略掉来view的mOnTouchListener,因为这个地方不会影响到dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent,我们可以理解为mOnTouchListener和onTouchEvent是一个方法就行,只是再执行的时候他们二选其一。

6.我们把down->move........move->up成为一个完整的touch事件。对于一个完整的touch事件,touch在被传递的时候看起来是有记录它的传递路径的功能。对于viewgroup和view,我们不去重写它的方法,touch记录传递路径的功能有以下规律:

6a、如果down事件没有被任何一个view消化而被抛到最外面,那么不会有move和up事件。

6b、down事件被哪个view(包含viewgroup,因为viewgroup继承自view)消化,以后的move和up事件都会被这个view消化。

6c、如果down事件被消化了,后续的move和up会被传递到同一个方法里,但是传递的路径可能会不一样,可能会少经历一些方法。

demo下载路径:http://download.csdn.net/detail/u011647962/8440275

写在最后

博客都写来20多篇了,一个回复都木有,很受伤啊,各位道友看到了给个回复啊,作为对一个菜鸟的鼓励。顺便说声:大家,过年好。

时间: 2024-10-08 16:30:53

菜鸟进阶之Android Touch事件传递(二)的相关文章

菜鸟进阶之Android Touch事件传递(三)

费了这么大劲,终于写完了,这是我的原创.转载请说明出处:http://blog.csdn.net/bingospunky/article/details/44156771 这是touch传递系列文章的第三篇,我打算在这篇文章里从源码的角度解释dispatchTouchEvent.onInterceptTouchEvent.onTouchEvent方法的返回值影响touch传递的原理. 如果想了解touch和click的那些事,请浏览touch事件传递系列的第一篇http://blog.csdn.

菜鸟进阶之Android Touch事件传递(四)

尊重他人劳动成果,转载请说明出处:http://blog.csdn.net/bingospunky/article/details/44343477 在该系列文章第四篇,我准备介绍一下viewpager的touch事件处理. 如果想了解touch和click的那些事,请浏览touch事件传递系列的第一篇http://blog.csdn.net/bingospunky/article/details/43603397 如果想了解touch事件一步一步传递的路线,请浏览touch事件传递系列的第二篇

Android Touch事件传递机制 二:单纯的(伪生命周期)

转载于:http://blog.csdn.net/yuanzeyao/article/details/38025165 在前一篇文章中,我主要讲解了Android源码中的Touch事件的传递过程,现在我想使用一个demo以及一个实例来学习一下Andorid中的Touch事件处理过程. 在Android系统中,和Touch事件分发和处理紧密相关的三个函数如下:(1) public boolean dispatchTouchEvent(MotionEvent ev)(2) public boolea

Android touch 事件传递机制

前言: (1)在自定义view的时候经常会遇到事件拦截处理,比如在侧滑菜单的时候,我们希望在侧滑菜单里面有listview控件,但是我们希望既能左右滑动又能上下滑动,这个时候就需要对触摸的touch事件进行拦截.这个时候我们就需要明白android touch 事件传递机制, (2)以前很多时候比较模糊,也许是网上看到也有很多事件传递的相关文章,但我看着头晕,解释不彻底,有的说得一半,总算不满足不满意,于是据我自己的理解来彻底的来整理下具体的是怎么个传递方式,分享给大家,希望大家看到有什么不对的

【转】Android Touch事件传递机制解析

原文地址:http://www.cnblogs.com/runssnail/p/4250549.html 说明:本文在原文地址上有所改动 一.小故事 在讲正题之前我们讲一段有关任务传递的小故事,抛砖迎玉下: 话说一家软件公司,来一个任务,分派给了开发经理去完成 开发经理拿到,看了一下,感觉好简单,于是 开发经理:分派给了开发组长 开发组长:分派给了自己组员(程序员) 程序员:分派给了自己带的实习生. 实习生:好苦逼,无法分派,怎么办啊?只能自己干了 但是实习生能不能做好,有两种情况了. 情况一:

Android Touch事件传递机制详解 下

尊重原创:http://blog.csdn.net/yuanzeyao/article/details/38025165 资源下载:http://download.csdn.net/detail/yuanzeyao2008/7660997 在前一篇文章中,我主要讲解了Android源码中的Touch事件的传递过程,现在我想使用一个demo以及一个实例来学习一下Andorid中的Touch事件处理过程. 在Android系统中,和Touch事件分发和处理紧密相关的三个函数如下:(1) public

Android Touch事件传递机制通俗讲解

在讲正题之前我们讲一段有关任务传递的小故事,抛砖迎玉下: 话说一家软件公司,来一个任务,分派给了开发经理去完成: 开发经理拿到,看了一下,感觉好简单,于是 开发经理:分派给了开发组长 开发组长:分派给了自己组员(程序员) 程序员:分派给了自己带的实习生. 实习生:好苦逼,无法分派,怎么办啊?只能自己干了 但是实习生能不能做好,有两种情况了. 情况一: 实习生:经过一段时间的研究,琢磨,熬夜,奋斗,死敲,皇天不负有心人啊,完成了. 后来又来一个类似的任务,也按着这样传递下去了(开发经理->开发组长

Android Touch事件传递机制详解 上

尊重原创:http://blog.csdn.net/yuanzeyao/article/details/37961997 最近总是遇到关于Android Touch事件的问题,如:滑动冲突的问题,以前也花时间学习过Android Touch事件的传递机制,可以每次用起来的时候总是忘记了,索性自己总结一下写篇文章避免以后忘记了,其实网上关于Touch事件的传递的文章真的很多,但是很少有系统性的,都是写了一个简单的demo运行了一下,对于我们了解Android Touch事件基本上没有任何帮助. 今

android Touch事件传递小结

这次还是先贴上测试代码吧.. 主布局文件是个三层结构,最外层和中间层都是LinearLayout的子类,里层是个TextView: <com.example.touchevent.OutterLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/o