android事件分发机制详解
来源:互联网 发布:淘宝 香港 编辑:程序博客网 时间:2024/04/29 14:38
android系统的点击事件是由最初的硬件触发的,然后 传递给屏幕最外缘的ViewGroup 继而往下传递,直到最底层的View然后向上回传。
整个过程可以分为:
viewGroup-->dispatchTouchEvent()
viewgroup-->onInterceptTouchEvent()
……
……
view-->dispatchTouchEvent()
view-->onTouchEvent()
viewGroup-->onTouchEvent()
简单说下几个方法的作用:
dispatchTouchEvent() 主要负责事件的传递
onInterceptTouchEvent() 主要负责事件的拦截
onTouchEvent() 主要负责事件的处理
在一个ViewGroup中可以包含上述的三种方法,包括事件的传递、拦截和处理。而在一个view中只有事件的传递和事件的处理而没有事件的拦截方法,因为view里面无法包含其他view了哦。
一个点击事件默认是从dispatchTouchEvent() 开始的然后由onInterceptTouchEvent() 做拦截处理向下传递。
@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {Log.d("ViewGroup1", "dispatchTouchEvent");return super.dispatchTouchEvent(ev);}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {Log.d("ViewGroup1", "onInterceptTouchEvent");return super.onInterceptTouchEvent(ev);}@Overridepublic boolean onTouchEvent(MotionEvent event) {Log.d("ViewGroup1", "onTouchEvent");return super.onTouchEvent(event);}
1.三个方法的默认返回值都为false,都是默认不做拦截和处理。
2.当spatchTouchEvent() 返回true时,当前的事件在当前的View(ViewGroup)中的spatchTouchEvent() 中处理,不再向下做任何处理,即事件在此处结束。
3.当spatchTouchEvent() 返回false,而且onInterceptTouchEvent()也返回false时,事件回向下继续传递。
当spatchTouchEvent() 返回false,而且onInterceptTouchEvent()也返回true时,事件将会交给此处View(ViewGroup)的onTouchEvent() 处理。
4.当事件交给onTouchEvent() 后,事件将不会再往下继续传递,onTouchEvent() 的返回值决定事件是否继续往上传递,如果onTouchEvent() 返回false则事件可以继续向上传递,上层的viewGroup可以决定是否对事件进行处理。
当onTouchEvent() 返回值为true时事件将不会再继续往上传递。
看了这么多字相信大家都会觉得很绕,那么下面用一个例子说明下。
故事篇:可怜的小明
在学校班主任向班长交代了一些打扫学习的任务,班长自己不想做就把这些任务交给学生小明,小明没办法就的去完成任务啊,小明很负责地完成任务后,把完成任务的消息告诉了班长,班长最后告诉了班主任,最后班主任很高兴地夸奖了班长。
好了,听了刚才的故事,我们可以把班主任当作为最外层的ViewGroup把班长当作内层的ViewGroup,小明就只能是最内层的View咯。
我们可以自定义一个ViewGroup1作为班主任,VeiwGroup2作为班长,自定义view作为可怜的小明,ViewGroup分别重写里面的dispatchTouchEvent() ,onInterceptTouchEvent() 和onTouchEvent() 方法,而View则重写dispatchTouchEvent() ,和onTouchEvent() 方法。
ViewGroup1
<span style="font-family:Microsoft YaHei;font-size:14px;">package com.flyou.touchmode;import android.annotation.TargetApi;import android.content.Context;import android.os.Build;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.ViewGroup;import android.widget.LinearLayout;/** * ============================================================ * 项目名称:OrmListeDemo * 包名称:com.flyou.touchmode * 文件名:ViewGroup1 * 类描述: * 创建人:flyou * 邮箱:fangjaylong@gmail.com * 创建时间:2015/9/16 14:51 * 修改备注: * 版本:@version V1.0 * ============================================================ */public class ViewGroup1 extends LinearLayout { public ViewGroup1(Context context) { super(context); } public ViewGroup1(Context context, AttributeSet attrs) { super(context, attrs); } public ViewGroup1(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public ViewGroup1(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.d("ViewGroup1", "dispatchTouchEvent"); return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Log.d("ViewGroup1", "onInterceptTouchEvent"); return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.d("ViewGroup1", "onTouchEvent"); return super.onTouchEvent(event); }}</span>
ViewGroupe2
<span style="font-family:Microsoft YaHei;font-size:14px;">package com.flyou.touchmode;import android.annotation.TargetApi;import android.content.Context;import android.os.Build;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.ViewGroup;import android.widget.LinearLayout;/** * ============================================================ * 项目名称:OrmListeDemo * 包名称:com.flyou.touchmode * 文件名:ViewGroup2 * 类描述: * 创建人:flyou * 邮箱:fangjaylong@gmail.com * 创建时间:2015/9/16 14:54 * 修改备注: * 版本:@version V1.0 * ============================================================ */public class ViewGroup2 extends LinearLayout { public ViewGroup2(Context context) { super(context); } public ViewGroup2(Context context, AttributeSet attrs) { super(context, attrs); } public ViewGroup2(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public ViewGroup2(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.d("ViewGroup2", "dispatchTouchEvent"); return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Log.d("ViewGroup2", "onInterceptTouchEvent"); return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.d("ViewGroup2", "onTouchEvent"); return super.onTouchEvent(event); }}</span>
<span style="font-family:Microsoft YaHei;font-size:14px;">package com.flyou.touchmode;import android.annotation.TargetApi;import android.content.Context;import android.os.Build;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;/** * ============================================================ * 项目名称:OrmListeDemo * 包名称:com.flyou.touchmode * 文件名:View * 类描述: * 创建人:flyou * 邮箱:fangjaylong@gmail.com * 创建时间:2015/9/16 14:55 * 修改备注: * 版本:@version V1.0 * ============================================================ */public class View extends android.view.View{ public View(Context context) { super(context); } public View(Context context, AttributeSet attrs) { super(context, attrs); } public View(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public View(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.d("View", "dispatchTouchEvent"); return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { Log.d("View", "onTouchEvent"); return super.onTouchEvent(event); }}</span>
然后在Activity中使用他们
<span style="font-family:Microsoft YaHei;font-size:14px;">package com.flyou.touchmode;import android.graphics.Color;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.Menu;import android.view.MenuItem;public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); View view =new View(MainActivity.this); view.setBackgroundColor(Color.RED); ViewGroup2 viewGroup2=new ViewGroup2(MainActivity.this); viewGroup2.setBackgroundColor(Color.BLUE); viewGroup2.addView(view, 200, 200); ViewGroup1 viewGroup1=new ViewGroup1(MainActivity.this); viewGroup1.setBackgroundColor(Color.GREEN); viewGroup1.addView(viewGroup2, 350, 350); setContentView(viewGroup1); }}</span>
效果如下图所示
当我们点击红色区域时可以看到如下的Log
09-16 17:27:45.223 24157-24157/com.flyou.touchmode D/ViewGroup1﹕ dispatchTouchEvent
09-16 17:27:45.223 24157-24157/com.flyou.touchmode D/ViewGroup1﹕ onInterceptTouchEvent
09-16 17:27:45.223 24157-24157/com.flyou.touchmode D/ViewGroup2﹕ dispatchTouchEvent
09-16 17:27:45.223 24157-24157/com.flyou.touchmode D/ViewGroup2﹕ onInterceptTouchEvent
09-16 17:27:45.223 24157-24157/com.flyou.touchmode D/View﹕ dispatchTouchEvent
09-16 17:27:45.223 24157-24157/com.flyou.touchmode D/View﹕ onTouchEvent
09-16 17:27:45.223 24157-24157/com.flyou.touchmode D/ViewGroup2﹕ onTouchEvent
09-16 17:27:45.223 24157-24157/com.flyou.touchmode D/ViewGroup1﹕ onTouchEvent
从上述的log可以很清楚的看出,事件先有最外层的ViewGroup1的接受并往下传递,由最底层的view先开始处理,并往上传递。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
看到这里,相信大家对事件的传递机制已经有了一定的了解,可是小明的故事并没有结束,准确的说是还有其他情况。
故事番外篇:良心发现的班长
班长从班主任手中接过任务,自己本来还想交给小明来做的,可是突然间良心发现觉得总是欺负小明不好,于上就自己把校园给打扫了。
这样事件到班长就没有往下传递了,而是由班长完成再告诉班主任。
那么在我们的例子中应该怎么做呢?
从上述的3、4条我们可以得出,只需要将viewgroup2的onInterceptTouchEvent返回值 设置为true就ok了,这样子事件就不会在继续向下传递了。
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { Log.d("ViewGroup2", "onInterceptTouchEvent"); return true;// return super.onInterceptTouchEvent(ev); }
点击后得到如下输出。
09-16 17:38:01.911 5671-5671/com.flyou.touchmode D/ViewGroup1﹕ dispatchTouchEvent
09-16 17:38:01.911 5671-5671/com.flyou.touchmode D/ViewGroup1﹕ onInterceptTouchEvent
09-16 17:38:01.911 5671-5671/com.flyou.touchmode D/ViewGroup2﹕ dispatchTouchEvent
09-16 17:38:01.911 5671-5671/com.flyou.touchmode D/ViewGroup2﹕ onInterceptTouchEvent
09-16 17:38:01.911 5671-5671/com.flyou.touchmode D/ViewGroup2﹕ onTouchEvent
09-16 17:38:01.911 5671-5671/com.flyou.touchmode D/ViewGroup1﹕ onTouchEvent
由上述的例子,我们可以很清楚的看出,onInterceptTouchEvent的返回值决定了是否对事件进行拦截处理。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
看到这里想必大家对事件的传递机制有了进一步的了解,但是小明的故事并没有结束,让我们继续看看
故事番外篇:小明的愤怒
这天班长又来给小明交代任务了,小明很清楚的知道这任务是班主任交给班长做的,不是给自己的,小明很生气,但是又不敢不做啊,于是就闷头把任务做完了,但是小明越想越生气,最后一气之下就没有把做完的事情告诉班长。然后班长也没法告诉班主任任务完成了,然后班长就挨骂了,哈哈。
从上面的故事我们可以很清楚的看到是View自己把事件给处理了,并且没有交给父类控件处理,有上面的3、4条我们很容易得出方案。
只需要将onTouchEvent的返回值改为true就ok了
<span style="font-size:14px;"> @Override public boolean onTouchEvent(MotionEvent event) { Log.d("View", "onTouchEvent");return true;// return super.onTouchEvent(event); }</span>
09-16 17:48:42.447 15652-15652/com.flyou.touchmode D/ViewGroup1﹕ dispatchTouchEvent
09-16 17:48:42.447 15652-15652/com.flyou.touchmode D/ViewGroup1﹕ onInterceptTouchEvent
09-16 17:48:42.447 15652-15652/com.flyou.touchmode D/ViewGroup2﹕ dispatchTouchEvent
09-16 17:48:42.447 15652-15652/com.flyou.touchmode D/ViewGroup2﹕ onInterceptTouchEvent
09-16 17:48:42.447 15652-15652/com.flyou.touchmode D/View﹕ dispatchTouchEvent
09-16 17:48:42.447 15652-15652/com.flyou.touchmode D/View﹕ onTouchEvent
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
看到这里想必大家已经非常熟悉事件的分发机制了,最后我们就来说说dispatchTouchEvent的用法,dispatchTouchEvent是用来传递消息的,如果返回false则默认向下传递,如果返回true,则直接拦截被自己处理。
故事番外篇:小明不干了
经过上一次的事件之后,班长挨了班主任的骂,班长对小明记恨在心,出处为难小明,这天班主任又给班长打扫厕所的任务,班长当然不会自家干了啊,于是就像到了小明,便把打扫厕所的事交给了小明,小明一听,艹 老子不干,再也不干了!!!
又上述可见,小明是没有对事件进行处理的,班长、和班主任也没有得到事件的反馈,事件到小明这里就结束了。
又上述的第2条,我们可以很容易的只要将View的 dispatchTouchEvent的返回值设为true就ok了
<pre name="code" class="java"> @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.d("View", "dispatchTouchEvent");return true;// return super.dispatchTouchEvent(event); }
09-16 17:56:52.679 23564-23564/com.flyou.touchmode D/ViewGroup1﹕ dispatchTouchEvent
09-16 17:56:52.679 23564-23564/com.flyou.touchmode D/ViewGroup1﹕ onInterceptTouchEvent
09-16 17:56:52.679 23564-23564/com.flyou.touchmode D/ViewGroup2﹕ dispatchTouchEvent
09-16 17:56:52.679 23564-23564/com.flyou.touchmode D/ViewGroup2﹕ onInterceptTouchEvent
09-16 17:56:52.679 23564-23564/com.flyou.touchmode D/View﹕ dispatchTouchEvent
还是上面的几点:
1.三个方法的默认返回值都为false,都是默认不做拦截和处理。
2.当spatchTouchEvent() 返回true时,当前的事件在当前的View(ViewGroup)中的spatchTouchEvent() 中处理,不再向下做任何处理,即事件在此处结束。
3.当spatchTouchEvent() 返回false,而且onInterceptTouchEvent()也返回false时,事件回向下继续传递。
当spatchTouchEvent() 返回false,而且onInterceptTouchEvent()也返回true时,事件将会交给此处View(ViewGroup)的onTouchEvent() 处理。
4.当事件交给onTouchEvent() 后,事件将不会再往下继续传递,onTouchEvent() 的返回值决定事件是否继续往上传递,如果onTouchEvent() 返回false则事件可以继续向上传递,上层的viewGroup可以决定是否对事件进行处理。
当onTouchEvent() 返回值为true时事件将不会再继续往上传递。
就这样,小明最后逃出了班长的恶爪,赢取了白富美,过上了幸福的生活。
好了,这就是小明的故事……
- Android 事件分发机制详解
- Android事件分发机制详解
- Android事件分发机制详解
- Android 事件分发机制详解
- Android 事件分发机制详解
- android事件分发机制详解
- Android 事件分发机制详解
- Android 事件分发机制详解
- Android事件分发机制详解
- Android事件分发机制详解
- android事件分发机制详解
- Android事件分发机制详解
- Android事件分发机制详解
- android 事件分发机制详解
- Android事件分发机制详解
- Android事件分发机制详解
- Android事件分发机制详解
- Android事件分发机制详解
- 在unity3d中引入第三方dll
- CentOS6.5下安装Nginx
- 查看Linux系统日志
- 自定义按钮,模拟系统消息提醒
- 细谈Hibernate(二)开发第一个hibernate基本详解
- android事件分发机制详解
- ubuntu下文件压缩/解压缩命令总结
- LIST接口及其子类
- 剑指 offer:反转链表
- linux创建新进程的过程
- HDOJ 3374 String Problem
- Android 打造编译时注解解析框架 这只是一个开始
- 取消系统自动对齐字节
- 编程修养