Android 事件拦截

概念介绍

1、onInterceptTouchEvent()是用于处理事件(重点onInterceptTouchEvent这个事件是从父控件开始往子控件传的,直到有拦截或者到没有这个事件的view,然后就往回从子到父控件,这次是onTouch的)(类似于预处理,当然也可以不处理)并改变事件的传递方向,也就是决定是否允许Touch事件继续向下(子控件)传递,一但返回True(代表事件在当前的viewGroup中会被处理),则向下传递之路被截断(所有子控件将没有机会参与Touch事件),同时把事件传递给当前的控件的onTouchEvent()处理;返回false,则把事件交给子控件的onInterceptTouchEvent()

2、onTouchEvent()用于处理事件(重点onTouch这个事件是从子控件回传到父控件的,一层层向下传),返回值决定当前控件是否消费(consume)了这个事件,也就是说在当前控件在处理完Touch事件后,是否还允许Touch事件继续向上(父控件)传递。返回false,则向上传递给父控件,详细一点就是这个touch事件就给了父控件,那么后面的up事件就是到这里touch触发,不会在传给它的子控件。如果父控件依然是false,那touch的处理就给到父控件的父控件,那么up的事件处理都在父控件的父控件,不会触发下面的。

返回true,如果是子控件返回true,那么它的touch事件都在这里处理,父控件是处理不了,因为它收不到子控件传给他的touch,被子控件给拦截了。(这里啰嗦了这么多就是为了加深记忆,这个两个事件理解起来都这么麻烦了,更何况去记,记我肯定是一下子就忘的了^0^)

(注:可能你会觉得是否消费了有关系吗,反正我已经针对事件编写了处理代码?答案是有区别!比如ACTION_MOVE或者ACTION_UP发生的前提是一定曾经发生了ACTION_DOWN,如果你没有消费ACTION_DOWN,那么系统会认为ACTION_DOWN没有发生过,所以ACTION_MOVE或者ACTION_UP就不能被捕获。)

详细介绍

onInterceptTouchEvent()是ViewGroup的一个方法,目的是在系统向该ViewGroup及其各个childView触发onTouchEvent()之前对相关事件进行一次拦截,Android这么设计的想法也很好理解,由于ViewGroup会包含若干childView,因此需要能够统一监控各种touch事件的机会,因此纯粹的不能包含子view的控件是没有这个方法的,如LinearLayout就有,TextView就没有。

onInterceptTouchEvent()使用也很简单,如果在ViewGroup里覆写了该方法,那么就可以对各种touch事件加以拦截。但是如何拦截,是否所有的touch事件都需要拦截则是比较复杂的,touch事件在onInterceptTouchEvent()和onTouchEvent以及各个childView间的传递机制完全取决于onInterceptTouchEvent()和onTouchEvent()的返回值。并且,针对down事件处理的返回值直接影响到后续move和up事件的接收和传递。

关于返回值的问题,基本规则很清楚,如果return true,那么表示该方法消费了此次事件,如果return false,那么表示该方法并未处理完全,该事件仍然需要以某种方式传递下去继续等待处理。

onInterceptTouchEvent()是ViewGroup的一个方法,目的是在系统向该ViewGroup及其各个childView触发onTouchEvent()之前对相关事件进行一次拦截。

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

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

如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return true,那么后续的move, up等事件将不再传递给该ViewGroup的onInterceptTouchEvent(),而是和down事件一样传递给该ViewGroup的onTouchEvent()处理,注意,目标view将接收不到任何事件。(这里的意思是说,只要被拦截了,当前onInterceptTouchEvent()方法将不会再被回调)

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

如果最终需要处理事件的view 的onTouchEvent()返回了true,那么后续事件将可以继续传递给该view的onTouchEvent()处理。(比如我down事件返回了true,那我的move逻辑将会被接下来调用,如果move返回true,那么继续up,如果move返回false,那么就传递给上一层次View的onTouchEvent()处理)。

仅仅看这个官方文档解释,就能理解清楚这两个函数关系以及用途的绝对是富有经验的framework高手。

否则,一定需要一个案例来阐释。假设我们有这样一个layout,用一个示例图来解释这个layout:

通常外围的layoutview1,layoutview2,只是布局的容器不需要响应触屏的点击事件,仅仅Mytextview需要相应点击。但这只是一般情况,一些特殊的布局可能外围容器也要响应,甚至不让里面的mytextview去响应。更有特殊的情况是,动态更换响应对象。

那么首先看一下默认的触屏事件的在两个函数之间的传递流程。如下图:

如果仅仅想让MyTextView来响应触屏事件,让MyTextView的OnTouchEvent返回true,那么事件流就变成如下图,可以看到layoutview1,layoutview2已经不能进入OnTouchEvent:

另外一种情况,就是外围容器想独自处理触屏事件,那么就应该在相应的onInterceptTouchEvent函数中返回true,表示要截获触屏事件,比如layoutview1作截获处理,处理流变成如下图:

以此类推,我们可以得到各种具体的情况,整个layout的view类层次中都有机会截获,而且能看出来外围的容器view具有优先截获权。

当我们去做一些相对来讲具有更复杂的触屏交互效果的应用时候,经常需要动态变更touch event的处理对象,比如launcher待机桌面和主菜单(见下图),从滑动屏幕开始到停止滑动过程当中,只有外围的容器view才可以处理touch event,否则就会误点击上面的应用图标或者widget.反之在静止不动的状态下则需要能够响应图标(子view)的touch事件。摘取framework中abslistview代码如下

publicbooleanonInterceptTouchEvent(MotionEventev){

intaction=ev.getAction();

switch(action&MotionEvent.ACTION_MASK){

caseMotionEvent.ACTION_DOWN:{

if(touchMode==TOUCH_MODE_FLING){

returntrue;//fling状态,截获touch,因为在滑动状态,不让子view处理

}

break;

}

caseMotionEvent.ACTION_MOVE:{

switch(mTouchMode){

caseTOUCH_MODE_DOWN:

finalintpointerIndex=ev.findPointerIndex(mActivePointerId);

finalinty=(int)ev.getY(pointerIndex);

if(startScrollIfNeeded(y-mMotionY)){

returntrue;//开始滑动状态,截获touch事件,不让子view处理

}

break;

}

break;

}

}

总结:

仅仅通过概览性的官方文档是很难理解onInterceptTouchEvent函数的用途的,只有通过演绎这个抽象的规则,配以图文才能获取这个重要的知识。很显然,默认是返回false,不做截获。返回true之后,事件流的后端控件就没有机会处理touch事件了,把默认的事件流中每个处理函数看作一个节点,这个节点只要返回true, 后续的事件就被截止了,这样想就很好理解。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容