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 boolean dispatchTouchEvent(MotionEvent ev)
(2) public boolean onInterceptTouchEvent(MotionEvent ev)
(3) public boolean onTouchEvent(MotionEvent event)
这三个方法我在前一篇文章中都对他们的源码进行了分析:方法1主要是对Touch事件进行分发,方法2主要是对Touch事件进行拦截,方法3是对Touch事件进行处理
这三个方法主要存在于ViewGroup,View,Activity中,具体情况如下图:
ViewGroup
View
Activity
dispatchTouchEvent
有
有
有
onInterceptTouchEvent
有
无
无
onTouchEvent
有
有
有
下面我们就使用一个demo来看看这些方法的执行流程:
自定义一个类:MyLayoutFirst.java
- public class MyLayoutFirst extends LinearLayout
- {
- private static final String TAG = "MyLayoutFirst";
- public MyLayoutFirst(Context context, AttributeSet attrs)
- {
- super(context, attrs);
- }
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev)
- {
- Log.w("yzy", "MyLayoutFirst->onInterceptTouchEvent->"+MyUtils.getActionName(ev));
- return super.onInterceptTouchEvent(ev);
- }
- @Override
- public boolean onTouchEvent(MotionEvent event)
- {
- Log.e("yzy", "MyLayoutFirst->onTouchEvent->"+MyUtils.getActionName(event));
- return super.onTouchEvent(event);
- }
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev)
- {
- Log.i("yzy", "MyLayoutFirst->dispatchTouchEvent->"+MyUtils.getActionName(ev));
- return super.dispatchTouchEvent(ev);
- }
- }
自定义一个类;MyLayoutSecond.java
- public class MyLayoutSecond extends LinearLayout
- {
- private static final String TAG = "MyLayoutSecond";
- public MyLayoutSecond(Context context, AttributeSet attrs)
- {
- super(context, attrs);
- }
- @Override
- public boolean onTouchEvent(MotionEvent event)
- {
- Log.e("yzy", "MyLayoutSecond->MyLayoutSecond->"+MyUtils.getActionName(event));
- return super.onTouchEvent(event);
- }
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev)
- {
- Log.w("yzy", "MyLayoutSecond->onInterceptTouchEvent->"+MyUtils.getActionName(ev));
- return super.onInterceptTouchEvent(ev);
- }
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev)
- {
- Log.i("yzy", "MyLayoutSecond->dispatchTouchEvent->"+MyUtils.getActionName(ev));
- return super.dispatchTouchEvent(ev);
- }
- }
加入到main_layout.xml中
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- >
- <com.event.demo.MyLayoutFirst
- android:id="@+id/layout_first"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#FF0000"
- >
- <com.event.demo.MyLayoutSecond
- android:id="@+id/layout_second"
- android:layout_width="320dip"
- android:layout_height="120dip"
- android:layout_gravity="center"
- android:background="#0000FF"
- >
- </com.event.demo.MyLayoutSecond>
- </com.event.demo.MyLayoutFirst>
- </RelativeLayout>
MainActivity中加入onTouchEvent方法
- public class MainActivity extends Activity
- {
- @Override
- protected void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- }
- @Override
- public boolean onCreateOptionsMenu(Menu menu)
- {
- // Inflate the menu; this adds items to the action bar if it is present.
- getMenuInflater().inflate(R.menu.main, menu);
- return true;
- }
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev)
- {
- Log.i("yzy", "MainActivity->dispatchTouchEvent->"+MyUtils.getActionName(ev));
- return super.dispatchTouchEvent(ev);
- }
- @Override
- public boolean onTouchEvent(MotionEvent event)
- {
- Log.e("yzy", "MainActivity->onTouchEvent->"+MyUtils.getActionName(event));
- return super.onTouchEvent(event);
- }
- }
最后就一个工具类,用来将事件id转换为字符串。
- public class MyUtils
- {
- private static final String TAG = "MyUtils";
- public static String getActionName(MotionEvent event)
- {
- String name="";
- switch(event.getAction())
- {
- case MotionEvent.ACTION_DOWN:
- name="ACTION_DOWN";
- break;
- case MotionEvent.ACTION_MOVE:
- name="ACTION_MOVE";
- break;
- case MotionEvent.ACTION_UP:
- name="ACTION_UP";
- break;
- }
- return name;
- }
- }
运行效果如图:
其中蓝色部分是MyLayoutSecond.java ,红色部分是MyLayoutFirst.java
现在我点击一下蓝色部分:运行结果如图:
从图中可以看出,事件最先被Activity捕获,然后分发给 MyLayoutFirst,MyLayoutFirst首先调用自身的onInterceptTouchEvent判断是否将该事件拦截,由于默认返回是false,所以没有拦截,从而事件分发给了MyLayoutSecond,MyLayoutSecond同样通过dispatchTouchEvent分发出去,分发出去之前同样检查是否被拦截,默认都是没有被拦截的,但是由于MyLayoutSecond是没有子视图的,所有最终事件有自己处理,调用自身的onTouchEvent方法,由于该方法默认返回的是false,所以认为此事件是没有被消费掉的,继续传递到了MyLayoutFirst中,同样也没有消费这个事件,最终传递到了Mainactivity,继续往后看发现后面的ACTION_MOVE和ACTION_UP并没有传入MyLayoutFirst和MyLayoutSecond,这是因为一旦某一个事件没有被处理,后面的事件是不会被分发的。所以ACTION_MOVE和ACTION_UP直接被MainActivity处理掉了。
下面再看第二种情况:
|
MainActivity |
MyLayoutFirst |
MyLayoutSecond |
|
|
dispatchTouchEvent |
super.dispatchTouchEvent |
super.dispatchTouchEvent |
super.dispatchTouchEvent |
|
onInterceptTouchEvent |
-- |
true |
super.onInterceptTouchEvent(ev) |
|
onTouchEvent |
super.onTouchEvent |
super.onTouchEvent |
super.onTouchEvent |
运行结果如下:
从图中可以看出,事件传递到了MyLayoutFirst后没有分发到MyLayoutSecond,直接调用自身的onTouchEvent,由于返回的是false,导致事件没有消费,最终传递给了MainActivity,
而且后续事件也没有传递到MyLayoutFirst和MyLayoutSecond,直接被MainActivity处理
第三种情况:
|
MainActivity |
MyLayoutFirst |
MyLayoutSecond |
|
|
dispatchTouchEvent |
super.dispatchTouchEvent |
super.dispatchTouchEvent |
super.dispatchTouchEvent |
|
onInterceptTouchEvent |
-- |
true |
super.onInterceptTouchEvent(ev) |
|
onTouchEvent |
super.onTouchEvent |
true |
super.onTouchEvent |
运行结果:
和情况二不同的是MyLayoutFirst的onTouchEvent返回了true,也就是说MyLayoutFirst消费了此事件,所以ACTION_DOWN也没有再传给MainActivity,并且ACTION_MOVE和ACTION_UP
均传给了MyLayoutFirst
第四中情况:
|
MainActivity |
MyLayoutFirst |
MyLayoutSecond |
|
|
dispatchTouchEvent |
super.dispatchTouchEvent |
super.dispatchTouchEvent |
super.dispatchTouchEvent |
|
onInterceptTouchEvent |
-- |
super.onInterceptTouchEvent(ev) |
super.onInterceptTouchEvent(ev) |
|
onTouchEvent |
super.onTouchEvent |
super.onTouchEven |
true |
运行结果:
发现所有的事件都是传递到了MyLayoutSecond后被消费了
其实还有很多其他组合方式,大家如果又兴趣可以自己尝试改变每个函数的返回值,查看打印结果,这里我就不一一列举了。。。。。
最后我会提供一个小demo演示如何解决滑动冲突,背景如下:
一个ViewPager里面包含两个Framgent,有一个Fragment里面有一个HorizontalListView ,如何滑动冲突?
我就贴出关键代码吧
- horizontal=(HorizontalListView)view.findViewById(R.id.hscroll);
- horizontal.setOnTouchListener(new OnTouchListener()
- {
- @Override
- public boolean onTouch(View arg0, MotionEvent event)
- {
- if(event.getAction()==MotionEvent.ACTION_DOWN)
- {
- parent.requestDisallowInterceptTouchEvent(true);
- }else if(event.getAction()==MotionEvent.ACTION_UP)
- {
- parent.requestDisallowInterceptTouchEvent(false);
- }
- return false;
- }
- });
加入这段代码就可以避免滑动冲突了,至于为什么大家可以参考我的前以前文章《Android Touch 事件传递机制详解 上》 这两个demo的例子我均会上传下载的
Android Touch事件传递机制详解 下的更多相关文章
- Android Touch事件传递机制详解 上
最近总是遇到关于Android Touch事件的问题,如:滑动冲突的问题,以前也花时间学习过Android Touch事件的传递机制,可以每次用起来的时候总是忘记了,索性自己总结一下写篇文章避免以后忘 ...
- Android Touch事件传递机制详解
Android开发的朋友经常处理各种触摸事件,然而在触摸事件的传递过程中主要用到三个方法:dispatchTouchEvent().onInterceptTouchEvent()和onTouchEve ...
- Android 的事件传递机制,详解
Android 的事件传递机制,详解 前两天和一个朋友聊天的时候.然后说到事件传递机制.然后让我说的时候,忽然发现说的不是非常清楚,事实上Android 的事件传递机制也是知道一些,可是感觉自己知道的 ...
- Android Touch事件传递机制具体解释 下
尊重原创:http://blog.csdn.net/yuanzeyao/article/details/38025165 资源下载:http://download.csdn.net/detail/yu ...
- Android Touch事件传递机制 二:单纯的(伪生命周期)
转载于:http://blog.csdn.net/yuanzeyao/article/details/38025165 在前一篇文章中,我主要讲解了Android源码中的Touch事件的传递过程,现在 ...
- Android Touch事件传递机制 二:单纯的(伪生命周期) 这个清楚一点
转载于:http://blog.csdn.net/yuanzeyao/article/details/38025165 在前一篇文章中,我主要讲解了Android源码中的Touch事件的传递过程,现在 ...
- Android事件传递机制详解及最新源码分析——ViewGroup篇
版权声明:本文出自汪磊的博客,转载请务必注明出处. 在上一篇<Android事件传递机制详解及最新源码分析--View篇>中,详细讲解了View事件的传递机制,没掌握或者掌握不扎实的小伙伴 ...
- Android Touch事件传递机制 一: OnTouch,OnItemClick(监听器),dispatchTouchEvent(伪生命周期)
ViewGroup View Activity dispatchTouchEvent 有 有 有 onInterceptTouchEvent 有 无 无 onTouchEvent 有 有 有 例 ...
- Android touch 事件传递机制
前言: (1)在自定义view的时候经常会遇到事件拦截处理,比如在侧滑菜单的时候,我们希望在侧滑菜单里面有listview控件,但是我们希望既能左右滑动又能上下滑动,这个时候就需要对触摸的touch事 ...
随机推荐
- ios开发学习笔记002-运算符
运算符 C语言有34种运算符,常见的有加减乘除. 算术运算符 1.加 10+2 2.减 20-2 3.乘 12*2 4.除 10/2 5.取余 10%3 = 1; 10%-3 = 1; -10%3 = ...
- Python基础-week01 Python安装/变量/输入/及循环语句使用
一.Python介绍 (1).目前Python主要应用领域: 云计算: 云计算最火的语言, 典型应用OpenStack WEB开发: 众多优秀的WEB框架,众多大型网站均为Python开发,You ...
- python-os模块及md5加密
常用内置方法 __doc__打印注释 __package__打印所在包 __cached__打印字节码 __name__当前为主模块是__name__ == __main__ __file__打印文件 ...
- [问题解决]NotImplementedError 错误原因:子类没有实现父类要求一定要实现的接口
NotImplementedError: 子类没有实现父类要求一定要实现的接口. 在面向对象编程中,父类中可以预留一个接口不实现,要求在子类中实现.如果一定要子类中实现该方法,可以使用raise No ...
- ERROR org.apache.hadoop.hdfs.server.datanode.DataNode: Incompatible namespaceIDs
用三台centos操作系统的机器搭建了一个hadoop的分布式集群.启动服务后失败,查看datanode的日志,提示错误:ERROR org.apache.hadoop.hdfs.server.dat ...
- Map的常用方法keySet()、entrySet()
Map是java中的接口,Map.Entry是Map的一个内部接口. Map提供了一些常用方法,如keySet().entrySet()等方法,keySet()方法返回值是Map中key值的集合:en ...
- 【bzoj1097】[POI2007]旅游景点atr 状压dp+堆优化Dijkstra
题目描述 FGD想从成都去上海旅游.在旅途中他希望经过一些城市并在那里欣赏风景,品尝风味小吃或者做其他的有趣的事情.经过这些城市的顺序不是完全随意的,比如说FGD不希望在刚吃过一顿大餐之后立刻去下一个 ...
- C#,一种简单的方式实现滚动鼠标缩放图片,平移
1.缩放 private void ImageShow_Load(object sender, EventArgs e) { pictureBox1.Load(@"E:\SQ1.jpg&qu ...
- mysql查看语句执行状态的常见函数
row_count() 返回上一个insert.update.delete语句的影响行数 found_rows() 返回上一个select查到的记录条数 last_insert_id() 返回上一次插 ...
- DOS头结构
DOS头结构typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header +0h WORD e_magic; ...