dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent消息分发知识基础(转自别人,本人适当添加或修改)

动作序列的三个事件

TouchEvent 分三种事件:down、move、up。

其中move事件在一个操作中(这里说的一个操作就是用户与屏幕的交互,即由down到up的动作序列)可能会发生多次。
但是,我们认为一个动作序列会包含以上三种事件,因此,在事件处理中就是要处理好这个过程,而最重要的就是down事件,这是一个动作序列的起始,没有down谈不上后面的事件了。
所以,我们把消耗down事件的类当做是这个动作序列的最终载体。

如果Down事件不归你处理,那这个动作序列的move,up也不归你处理。

他们的触发顺序会是这样:ACTION_DOWN->ACTION_MOVE->ACTION_MOVE->ACTION_MOVE...->ACTION_MOVE->ACTION_UP

 

从父到子的消息分发流程

Android 消息队列的分发流程是

Activity  ->  ViewGroup1  -> ViewGroup1的直接子ViewGroup –> ××××××  -> 叶子View

 消息和处理的一一对应

一个消息,默认消息都只需要一个控件来处理。中间消息途径的都只是起中转的效果,不做处理。处理完成直接返回了,不会通知中间步骤。

如果一个消息想改成多个控件都处理,则需要修改这里的逻辑

消息处理流程,从子到父

如果消息处理一直返回的是 false。

则一直是从子到父的依次处理。处理到没有可以处理的人了,或者返回了true到此为止。

比如:

如果一个Activity调用一个View,那么首先执行的是View中的onTouchEvent(MotionEvent event),如果返回false,

再执行Activity中的onTouchEvent(MotionEvent event),

否则不执行Activity中的onTouchEvent(MotionEvent event);

但是如果是触摸屏幕的标题栏的时候,执行的是Activity中onTouchEvent(MotionEvent event)。

Android 事件分发处理策略

Activity与View控件的分发流程有所区别,首先我们介绍 ViewGroup 的分发流程

 

Android ViewGroup分发处理原则

  • 默认情况,一个消息最后只需要一个人处理,其它消息途径者都只是干了中转的效果。
  • 消息传递途径三级处理机制:
    • 接受上级消息(dispatchTouchEvent),
    • 决策向下级分发还是自身处理(onInterceptTouchEvent),
    • 自身处理逻辑(onTouchEvent、onTouch 、onClick 、onLongClick 等)
  • View内部自身处理逻辑先后顺序,依次是:(注:在return不为true的情况下)
    • onTouchEvent
    • onClick
    • onLongClick
  • OnTouchListener onTouch onTouchEvent 的区别
    • 首先执行OnTouchListener()中的onTouch,然后执行重写的onTouchEvent(MotionEvent event)。(注:在return不为true的情况下)
    • onTouch() is used by users of the View to get touch events while onTouchEvent() is used by derived classes of the View to get touch events.
    • 更详细的可以看  http://blog.csdn.net/ddna/article/details/5451722
  • 消息处理中, return true 表示消息被完整地处理完成了,后面不用再用其他事件处理了。

方法功能说明:

 android系统中的每个View的子类都具有下面三个和TouchEvent处理密切相关的方法:

1)public boolean dispatchTouchEvent(MotionEvent ev)  这个方法用来分发TouchEvent
2)public boolean onInterceptTouchEvent(MotionEvent ev) 这个方法用来拦截TouchEvent
3)public boolean onTouchEvent(MotionEvent ev) 这个方法用来处理TouchEvent


dispatchKeyEvent是做分发的工作,如果你想要onKeyDown还可以接收到应该这样实现
public boolean dispatchKeyEvent(KeyEvent event){
            return super.dispatchKeyEvent(event);
    }


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


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

View,ViewGroup 的分发处理逻辑

对于每一个动作只有当这一个动作执行完这一系列方法的后,并且是按先执行父类的方法再执行子类的方法,才能去执行下一个动作,

这三个方法的执行顺序是:dispatchTouchEvent--〉InterceptTouchEvent--〉onTouchEvent

如:当子ViewonTouchEvent方法返回的是:false 

注释:OntouchLinearLayout为父VIEW,                    TextViewOnTouch为只子VIEW

08-05 15:10:03.865: I/OntouchLinearLayout(896): dispatchTouchEvent_ACTION_DOWN     注释1
08-05 15:10:03.865: I/OntouchLinearLayout(896): InterceptTouchEvent_ACTION_DOWN      2注释
08-05 15:10:03.865: I/TextViewOnTouch(896): dispatchTouchEvent_ACTION_DOWN       注释 3
08-05 15:10:03.865: I/TextViewOnTouch(896): onTouchEvent_ACTION_DOWN     注释 4
08-05 15:10:03.865: I/OntouchLinearLayout(896): onTouchEvent_ACTION_DOWN        注释5
08-05 15:10:03.954: I/OntouchLinearLayout(896): dispatchTouchEvent_ACTION_MOVE      注释 6
08-05 15:10:03.954: I/OntouchLinearLayout(896): onTouchEvent_ACTION_MOVE           注释7
08-05 15:10:03.975: I/OntouchLinearLayout(896): dispatchTouchEvent_ACTION_UP      注释8
08-05 15:10:03.975: I/OntouchLinearLayout(896): onTouchEvent_ACTION_UP            注释 9

打印说明:

当我们点击子View时,首先Activity将TouchEvent事件传递给最顶层的View,顶层的View的dispatchTouchEvent方法返回的是:Super.dispatchTouchEvent ,意味着由onInterceptTouchEvent决定事件流向,所以打印注释2,而onInterceptTouchEvent方法返回的而是:super.onInterceptTouchEvent(ev),表示自己无法完全处理,或者不能处理,继续下传传递到下子viewdispatchTouchEvent(),所以打印 注释 3,继续向下执行,而子View已经没有InterceptTouchEvent方法,所以打印  注释 4,对于后面的打印中为什么都没有子View打印了呢?因为我们这测试子 View的返回值是 false,这一返回值意味着:后续产生的其它事件将直接忽略掉这个View(不过LongPress又有另外的独立逻辑)。举例来说就是,如果你处理ACTION_DOWN时返回了false,那么你这个View将得不到ACTION_MOVE或ACTION_DOWN等等这些后续事件了。

现在我们再来看当 子ViewonTouchEvent方法返回的是:true

打印消息如下:

08-05 15:37:44.026: I/OntouchLinearLayout(924):dispatchTouchEvent_ACTION_DOWN
08-05 15:37:44.026: I/OntouchLinearLayout(924): InterceptTouchEvent_ACTION_DOWN
08-05 15:37:44.026: I/TextViewOnTouch(924): dispatchTouchEvent_ACTION_DOWN
08-05 15:37:44.026: I/TextViewOnTouch(924): onTouchEvent_ACTION_DOWN
08-05 15:37:44.115: I/OntouchLinearLayout(924): dispatchTouchEvent_ACTION_MOVE
08-05 15:37:44.115: I/OntouchLinearLayout(924): InterceptTouchEvent_ACTION_MOVE
08-05 15:37:44.115: I/TextViewOnTouch(924): dispatchTouchEvent_ACTION_MOVE
08-05 15:37:44.115: I/TextViewOnTouch(924): onTouchEvent_ACTION_MOVE
08-05 15:37:44.155: I/OntouchLinearLayout(924): dispatchTouchEvent_ACTION_UP
08-05 15:37:44.155: I/OntouchLinearLayout(924): InterceptTouchEvent_ACTION_UP
08-05 15:37:44.155: I/TextViewOnTouch(924): dispatchTouchEvent_ACTION_UP
08-05 15:37:44.155: I/TextViewOnTouch(924): onTouchEvent_ACTION_UP

从上面的消息中我们可以看出,当子View的onTouchEvent方法返回的是true时,是可以处理子VIEW的其它动作


二:

如果父VIEW的dispatchTouchEvent方法返回false。打印消息如下:

08-05 15:56:07.977: I/OntouchLinearLayout(1053): dispatchTouchEvent_ACTION_DOWN

它根本就没不会再执行它后面的其它两个方法,及子VIEW的这些方法了

如果是子VIEW的 dispatchTouchEvent方法返回false(此时父VIEW的dispatchTouchEvent是返回super.dispatchTouchEvent(ev))。打印消息如下

08-05 16:10:31.275: I/OntouchLinearLayout(1109): dispatchTouchEvent_ACTION_DOWN
08-05 16:10:31.275: I/OntouchLinearLayout(1109): InterceptTouchEvent_ACTION_DOWN
08-05 16:10:31.275: I/TextViewOnTouch(1109): dispatchTouchEvent_ACTION_DOWN
08-05 16:10:31.275: I/OntouchLinearLayout(1109): onTouchEvent_ACTION_DOWN


 

  • dispatchTouchEvent(默认返回值是true)

 

接受上级传递过来的消息
抽象对象的对外调用接口。

对外部来说,只知道这个接口,不知道其他。相当于企业门卫,

邮递员是把信给门卫的。

1、返回值:false 
不接受动作序列中的后续事件

我们一般遇到事件有3种,分别是:Down、move、up False表示

不接受动作序列中的后续事件,因此本次后续操作不起作用,

如:down后返回false,则move和up都不会被接受,(此VIEW或此View的子VIEW)后面的onInterceptTouchEvent,onTouchEvent也不执行了,(请看测试二)


2、返回值:true  
继续接受动作序列中的后续事件,如move、up

其中如果调用了Super.dispatchTouchEvent。 这样就会继续调用

onInterceptTouchEvent事件。
如果返回值是 Super.dispatchTouchEvent ,

意味着由onInterceptTouchEvent决定事件流向,

Super.dispatchTouchEvent 的返回值就是系统默认的,

系统默认最终只有一个控件处理这个消息。
如果需要多个控件同时处理,则一定需要返回true,

并调用Super.dispatchTouchEvent

 

  • onInterceptTouchEvent(默认返回值是false)
抽象对象对内的接口。
相当其企业的内勤,负责分发信件。

不过要注意的是,一旦动作序列的down事件知道了该如何分发,

下次就会绕过它

返回值:true

自己处理,不需要继续下传
事件会传递到自己的onTouchEvent()

Down事件在onInterceptTouchEvent()后返回true,则传递到onTouchEvent,

当其返回true时,动作序列的后续事件不会再通过onInterceptTouchEvent了,

而是在dispatchTouchEvent中直接传递于onTouchEvent。
返回值:false
自己无法完全处理,或者不能处理,继续下传

传递到下一个view的dispatchTouchEvent()

onInterceptTouchEvent返回false应该传给下个子view的dispatchTouchEvent,

但是,点击的叶子节点view,因此不存在子view而直接传给自己的onTouchEvent

onInterceptTouchEvent要做的就是确定事件传递到哪个子view,如果返回false,

又没有子view处理(因为根本就没有点击到子view),就自己处理了,而自己在onTouchEvent处理的后续事件就不必经过onInterceptTouchEvent了,

它是判断传递给子view的,都不是子view处理,就不用经过了。

 

  • onTouchEvent(默认返回值是false)
  • 实现View.OnClickListener 的onClick
  • 实现View.OnLongClickListener 的 onLongClick
  • 实现View.OnTouchClickListener 的 onTouch
具体干事的
这里有个先后顺序。
如果先工作的把这件事情结束了,就不会继续传递下去了。

如果我们在一个View中同时覆写了onClick、onLongClick及onTouchEvent的话,onTouchEvent是最先捕捉到ACTION_DOWN和ACTION_UP事件的,

其次才可能触发onClick或者onLongClick。

返回值 true和false在其中起着标志事件是否被消耗,
如果消耗了就不再传递给其他控件了。
如果没有消耗则还会传递给其他控件,触发其他控件的事件处理函数。

 

参考资料

Android onTouchEvent, onClick及onLongClick的调用机制
http://blog.csdn.net/ddna/article/details/5451722

 

android 事件处理
http://blog.csdn.net/leesidong/article/details/6973261

 

Android FrameWork——Touch事件派发过程详解
http://blog.csdn.net/stonecao/article/details/6759189

 

Android中Touch事件的处理逻辑
http://www.oschina.net/question/163910_27289


Android ViewGroup中事件触发和传递机制

http://www.cnblogs.com/lovelili/archive/2012/08/02/2620289.html



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值