MotionEvent.ACTION_DOWN//按下事件
MotionEvent.ACTION_MOVE//移动事件
//结束事件
MotionEvent.ACTION_UP://按下直接抬
MotionEvent.ACTION_CANCEL://事件被上层节点intercept了,我收不到event了,也就cancel了
然后,再了解,android的事件是怎么传播的
不多说概念,直接上流程
一 、MotionEvent.ACTION_DOWN(按下事件)
- 第一步当然是处理
MotionEvent.ACTION_DOWN
事件,由事件所在的 活动 调用dispatchTouchEvent(MotionEvent event)
准备 分发这个按下事件(如果不被onInterceptTouchEvent拦截)事件会分发到view树结构至事件发生的最小view节点的方法中,这一相关的view节点树结构,我在此文章称之为 事件分发view节点树。 - 事件分发到ViewGroup类型的节点时,节点会接收到Activity发来的按下事件会 依序 分发到自身的2个方法 中,方法如下所示
public boolean dispatchTouchEvent(MotionEvent event)
//此方法默认返回super.dispatchTouchEvent(event)public boolean onInterceptTouchEvent(MotionEvent ev)
//如果在此方法中返回true就代表拦截事件分发,也就意味事件分发在此类型为viewGroup的view节点中断,不会继续沿着事件分发view节点树向下分发此事件。
- 如果一切顺利没人拦截事件分发到最小View节点时,节点会调用最小节点的如下所示方法
dispatchTouchEvent(MotionEvent event)
- 如果事件分发view节点树没被拦截,那就是由最小view节点中的
public boolean onTouchEvent(MotionEvent event)
作为起始节点沿着 事件分发view节点树向上分发,但是如果被拦截了,就由拦截的viewGroup节点public boolean onTouchEvent(MotionEvent event)
作为起始节点, 准备 把此按下事件向上分发给 事件分发view节点树 上的每个节点的public boolean onTouchEvent(MotionEvent event)
中,直到分发到根节点也就是Activity的public boolean onTouchEvent(MotionEvent event)
方法中为止。
但是只要有任意一个节点在自身的public boolean onTouchEvent(MotionEvent event)
方法中返回true,那么事件向上分发就会在此节点中断,也就意味着事件在事件分发view节点树上就只向上分发到此节点的public boolean onTouchEvent(MotionEvent event)
方法中为止,不会继续向上级节点分发这此事件。MotionEvent.ACTION_DOWN(用户按下)事件分发就此结束。
二、MotionEvent.ACTION_MOVE(移动事件)
第一步当然还是activity的事件分发dispatchTouchEvent(MotionEvent event)
,当然这次分发的是移动事件,不是按下事件,如果在MotionEvent.ACTION_DOWN(用户按下)
按下事件分发流程完毕后,事件分发view节点树上没有任何一个节点在自身的public boolean onTouchEvent(MotionEvent event)
方法返回true的话,就意味着没有view节点处理,那么Activity只会把事件分发给自身的public boolean onTouchEvent(MotionEvent event)
,反之,如果有某个节点在MotionEvent.ACTION_DOWN(用户按下)
事件分发流程中在自身的public boolean onTouchEvent(MotionEvent event)
返回true的话就意味着这移动事件在这个view节点中要被处理,用专业的词就就是移动事件要在此节点中被消费。所以activiy会把此移动事件根据事件分发view节点树分发至此返回true的节点为止,分发到此移动事件的viewGroup类型节点都会把这个移动事件依序发发到自身的 2 个方法中,方法如下所示。
public boolean dispatchTouchEvent(MotionEvent event)
public boolean onInterceptTouchEvent(MotionEvent event)
//可以用此方法拦截移动事件,拦截之后,Activity会重新分发移动事件直到此view节点的onTouchEvent为止。
但如果分发到事件的节点是view类型的节点(不太确定,想拦截事件直接在oninter返回true就行了)或者是在onInterceptTouchEvent返回ture的节点的上级节点,那么就只会调用以下所示方法(dispaev),通俗的说就是事件以被此节点拦截了,事件只会分发到此节点的上级包括自身的dispatchTouchEvent方法,不会调用节点onInterceptEvent方法,最后发送到自身节点的onTouchEvent方法为止,无论返回什么值都不会继续传到上级节点的ontouchevent。为什么呢?一个事件被拦截了,就代表此由此节点处理接下来的手势了,上级节点以及下级节点都能不处理了,如果下个move事件再次分发经过此上级节点事件如果能分发到onInterceptTouchevent或下级节点收到分发事件还有上级的ontouchevent,就会使当前想处理手势的节点无法正常接收move事件进行手势处理。
public boolean dispatchTouchEvent(MotionEvent event)
事件最后会分发给返回true的节点,此节点会调用自身的两个方法如下所示,最后由节点的public boolean onTouchEvent(MotionEvent event)
方法收到此移动事件后被调用后,此MotionEvent.ACTION_MOVE(移动事件)分发结束。不会继续向上级节点的ontouchevent分发事件。
分发结束后,我就可以在返回true的节点中的onTouchEvent方法,或 dispatchTouchEvent方法中进行触摸的业逻辑开发。public boolean dispatchTouchEvent(MotionEvent event)
public boolean onTouchEvent(MotionEvent event)
三、MotionEvent.ACTION_UP、MotionEvent.ACTION_CANCEL(结束事件)
结束事件的分发同 移动事件分发一样,在按下事件中onTouchEvent返回true的 节点中的onTouchEvent中为止。结束事件分发与移动事件分发同理
原理图示如下
再说明一个知识点
当一个view层级不够,被一个遮挡view遮挡住自身view时,如果这个遮挡view的在ontouchEvent MotionEvetnt.Action_Donwn中返回true。这个被遮挡的view就收不到Acton_move事件。因为遮挡view在接收onTouchEvent ACTION_DOWN事件要比被遮挡view先收到。(放弃坑太深了,action_move也不能放回true )
如图所示
参考文章
事件分发