安卓事件分发
来源:互联网 发布:手机室内建模软件 编辑:程序博客网 时间:2024/06/05 09:38
一、事件分发的相关方法
1、事件分发相关的方法:
1、dispatchTouchEvent 事件分发 2、onInterceptTouchEvent 事件拦截 (只有ViewGroup有) 3、onTouchEvent 事件处理
2、三个方法的作用:
既然要分析三个方法的作用,那么肯定要分析三个方法的方法内容与返回值了。
① onInterceptTouchEvent
先讲最简单的(只有ViewGroup中有),onInterceptTouchEvent方法的返回值表示当前ViewGroup是否要拦截事件,一旦拦截(返回true),那么本系列事件就不会分发到ViewGroup的子View中去(也有例外,在这先不讨论例外情况,先从最简单的开始理解)。那么,onInterceptTouchEvent的方法体中应该干嘛呢?也很简单,就是来判断什么时候应该让ViewGroup拦截事件。onInterceptTouchEvent的返回值默认是false(不拦截),也就是说,如果我们不去重写这个方法的话,它默认返回false(不拦截事件)。
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { boolean intercept = false; if(xxx){ //应该让ViewGroup拦截事件的条件 intercept = true; } return intercept; }
② onTouchEvent
这个方法也很简单,它的方法体是对事件的具体处理,返回值表示处理该事件(其实它的返回值没有太大意义,等具体分析dispatchTouchEvent时会说明该返回值的意义)。
@Override public boolean onTouchEvent(MotionEvent event) { switch(event.getAction()){ case MotionEvent.ACTION_DOWN: //处理手指摁下的操作 break; case MotionEvent.ACTION_MOVE: //处理手指移动的操作 break; case MotionEvent.ACTION_UP: //处理手指抬起的操作 break; } return true; }
③ dispatchTouchEvent
这个方法是整个事件分发的核心方法,dispatch英文名是分发的意思。那么它的方法内容和方法返回值又是什么呢?起什么样的作用呢?先来说说返回值,dispatchTouchEvent的返回值才是决定该View或者ViewGroup能否获得该事件的关键。
dispatchTouchEvent的返回值:
————返回true,上层的事件会依次传递下来,返回false,则上层的事件只会传递DOWN事件下来(当然,所有这些的前提是上层的ViewGroup没有拦截事件,因为一旦上层ViewGroup拦截了事件,那么下面的控件都不会接收到事件了)。
注意:dispatchTouchEvent虽然是分发事件的方法,但是其boolean返回值不是“是否要往下分发事件”的意思,而是“我是否需要接收该事件”的意思,是告诉上层ViewGroup是否要将事件传递给我
怎么理解呢?可以用一段白话文来帮助我们理解:
首先,ViewGroup的“上面”会问:“你是否需要该系列事件?”,即“上面”会通过自己的dispatchTouchEvent方法将“DOWN”事件分发传递进ViewGroup进行询问(这里可以将DOWN事件当作一名询问官),如果ViewGroup告诉“上面”:“我需要,你把事件都给我吧(即ViewGroup自己的dispatchTouchEvent返回true时)”。这时,“上面”会将该系列的事件依次传递进ViewGroup,ViewGroup拿到事件要怎么处理,就看ViewGroup自己的dispatchTouchEvent方法的方法体的实现了,一般调用super.dispatchTouchEvent按照系统的事件分发机制去处理,此时ViewGroup也会先去询问它的child:“你是否需要该组事件?”,即ViewGroup将“DOWN”传进子View去询问,如果子View的dispatch返回true,则说明子View需要,所有的事件都会通过ViewGroup再传给子View,此时,事件会从最上面一直传递给ViewGroup的dispatchTouchEvent再到子View的dispatchTouchEvent,如果子View的dispatchTouchEvent方法调用了super.dispatchTouchEvent(ev),则会调取子View的onTouchEvent的回调方法(本文只讨论这三大方法,不讨论在外面调用setOnTouchListener和setOnClickListener方法)。
dispatchTouchEvent默认时的伪代码:
ViewGroup的 public boolean dispatchTouchEvent(MotionEvent ev){ boolean consume = false; if(onInterceptTouchEvent(ev)){ //先判断是否拦截、拦截就直接执行自己的onTouchEvent方法 consume = onTouchEvent(ev); }else{ //如果不拦截、则执行子View或者ViewGroup的dispatchTouchEvent方法 consume = child.dispatchTouchEvent(ev); } return consume; } View的 public boolean dispatchTouchEvent(MotionEvent ev){ boolean consume = onTouchEvent(ev); return consume; }
从上面代码View的dispatchTouchEvent可以看到,为什么onTouchEvent也要有一个返回值,那是因为在dispatchTouchEvent的默认方法体中会调用onTouchEvent方法,并且onTouchEvent的返回值会影响到dispatchTouchEvent方法的返回值。如果我们重写dispatchTouchEvent方法:
public boolean dispatchTouchEvent(MotionEvent ev){ super.dispatchTouchEvent(ev); return true; }
此时事件仍然按照系统的分发机制去传递事件,但是dispatchTouchEvent的返回值已经写死了为true,那么此时,onTouchEvent方法的返回值就没有任何意义了。
3、事件分发相关的方法的默认代码:
@Override public boolean dispatchTouchEvent(MotionEvent ev) { return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { return super.onTouchEvent(event); }
所有的方法都只是调用了super的同名方法方法 dispatchTouchEvent(MotionEvent ev)中的super.dispatchTouchEvent(ev);就是调用的View或者ViewGroup的dispatchTouchEvent方法,即分发事件。只有调用了super.dispatchTouchEvent才会根据系统的分发逻辑去分发事件。方法 onInterceptTouchEvent(MotionEvent ev)中的super.onInterceptTouchEvent(ev);父类ViewGroup默认返回false,即不拦截。
public boolean onInterceptTouchEvent(MotionEvent ev) { return false; //默认值为false }
方法 onTouchEvent(MotionEvent event)中的super.onTouchEvent(event);是处理事件。
二、结合例子
例1
ViewGroup代码(使用默认的):
@Override public boolean dispatchTouchEvent(MotionEvent ev) { return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { return super.onTouchEvent(event); }
View的代码:
@Override public boolean dispatchTouchEvent(MotionEvent event) { return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { return true; }
只重写了View的onTouchEvent方法,返回true。
此时的分发逻辑:(分发只看dispatchTouchEvent方法)
1、由于View的onTouchEvent返回true,而View的dispatchTouchEvent方法使用的默认的super.dispatchTouchEvent(event) ,由于super.dispatchTouchEvent(event)中会调用onTouchEvent方法,返回值也受onTouchEvent方法返回值影响(可以根据上面的事件分发伪代码可以看出此处是相同的返回值),所以View的dispatchTouchEvent方法返回值为true。
2、因为ViewGroup的dispatchTouchEvent使用的默认,根据伪代码,它没有拦截事件,那么返回值就是子View的dispatchTouchEvent的返回值,因此ViewGroup的dispatchTouchEvent也返回true
3、当ViewGroup的“父ViewGroup”的“DOWN”来询问ViewGroup是否需要该组事件时,由于ViewGroup的dispatchTouchEvent返回true,因此ViewGroup表示需要该组事件,那么上面会将一系列的事件全部传入ViewGroup的dispatchTouchEvent中。
4、当ViewGroup拿到事件时,由于它调用了super.dispatchTouchEvent(event),所以它会遵循系统的分发机制先去询问子View是否需要该组事件,子View的dispatchTouchEvent返回了true,因此子View表示需要该组事件,那么ViewGroup会将一系列的事件传入子View的dispatchTouchEvent中。
5、由于子View的dispatchTouchEvent调用了super.dispatchTouchEvent(event),那么最终调用了子View的onTouchEvent方法,所有的事件都会在子View的onTouchEvent中去处理。
例2
ViewGroup代码(使用默认的):
@Override public boolean dispatchTouchEvent(MotionEvent ev) { return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { return super.onTouchEvent(event); }
View的代码:
@Override public boolean dispatchTouchEvent(MotionEvent event) { super.dispatchTouchEvent(event); return true; } @Override public boolean onTouchEvent(MotionEvent event) { // 处理事件 return false; }
这里重写了View的dispatchTouchEvent方法和onTouchEvent方法
此时的分发逻辑:
此时,View的onTouchEvent虽然返回false(我不处理事件),但是View的dispatchTouchEvent方法的返回值为true不受你 onTouchEvent返回值的影响,又dispatchTouchEvent方法体中调用了super.dispatchTouchEvent(event),因此所有的事件还是会传递进onTouchEvent方法中去(与你onTouchEvent的返回值无关,不管你是否要处理事件都得处理)。
例3
ViewGroup代码(使用默认的):
@Override public boolean dispatchTouchEvent(MotionEvent ev) { super.dispatchTouchEvent(ev); return false; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { return super.onTouchEvent(event); }
View的代码:
@Override public boolean dispatchTouchEvent(MotionEvent event) { super.dispatchTouchEvent(event); return true; } @Override public boolean onTouchEvent(MotionEvent event) { // 处理事件 return false; }
这里重写了ViewGroup的dispatchTouchEvent方法,View的dispatchTouchEvent方法和onTouchEvent方法
此时的分发逻辑:
由于ViewGroup的dispatchTouchEvent方法的返回值也是写死的为false,那么“上面”的DOWN事件传递下来询问ViewGroup是否需要事件时,ViewGroup拒绝消耗事件,上面就不会再传递事件下来了。此时,虽然子View的dispatchTouchEvent返回true,也是拿不到所有事件的。
这时,所有的事件只有DOWN事件会从“最上面”传递到ViewGroup的dispatchTouchEvent方法(因为DOWN相当于询问官来询问你是否需要的,不管你dispatchTouchEvent返回true还是false,DOWN都会传下来,当然有一种情况,就是ViewGroup将事件直接拦截了,那DOWN都不会传递下来了),然后传递给子View的dispatchTouchEvent方法,子View的dispatchTouchEvent将DOWN事件传递给自己的onTouchEvent。之后的所有事件都不会再传递下来了。
本文没有讨论子View中调用getParent().requestDisallowInterceptTouchEvent(true)来忽略ViewGroup的事件拦截,重点只是讨论的dispatchTouchEvent方法,如果要深入研究可以参考其他文章
- 安卓事件分发
- 安卓事件分发
- 安卓事件分发
- 安卓事件分发机制
- 安卓事件分发机制
- 安卓事件分发机制
- 安卓事件分发机制
- 安卓学习-事件分发
- 安卓事件分发框架
- 安卓事件分发机制
- 安卓事件分发机制
- 浅尝安卓事件分发机制
- Android:安卓Touch事件分发机制
- 安卓事件分发机制学习笔记
- **安卓事件分发机制学习**
- 浅尝安卓事件分发机制
- 安卓事件分发机制简解
- 安卓高级4 事件分发
- java 利用二进制位进行标记,获取不相同的随机数
- shape中gradient属性介绍
- HDU 3564 线段树+简单DP
- android: 横竖屏切换总结-布局改变和数据保存
- 文章标题
- 安卓事件分发
- java 读取 properties 文件方法 之一
- Android启动和关闭Activity
- [从头读历史] 第275节 诗经 秦风
- PostgreSQL 16进制数字转换
- jar包 路径配置
- IOS获取当前App的基本信息
- Java将字节数组转化为16进制字符串的多种方案
- Maven依赖调解