这里我们先将可以接收并处理Touch的view分个类
首先是起点(activity),然后是Layout等ViewGroup的子类,而最后一类则是最小的图形容器view.
而我们要讨论的Touch处理函数总有三种:
DispatchTouchEvent(MotionEvent ev),
OninterceptTouchEvent(Motion ev),
OnTouchEvent(MotionEvent ev);
其中OnInterceptTouchEvent(MotionEvent ev) 仅ViewGroup有。其它的三类都有。
那么Touch事件从何处开始呢?我们声明使用的对象,都是层层继承的下的子类。比如继承自ViewGroup的LinearLayout,RelativeLayou等。我们直接调用的是它们的三种Touch处理函数。所以在继承的时候想要其往下继续处理,就一定要使用Super继承调用父类函数。
那么我们就按流程来分析吧。首先,Activity启动。创建了我们所看到的UI类。然后等待我们的交互。当我们触碰就激活了Touch事件。首先由Activity中的dispatchTouchEvent 来分发。如果是Activity的子类重写则一定要加上Super.dispatchTouchEvent(ev);否则无论返回的是true还是false.则没有函数来处理该事件,造成所有touch失效。
然后呢事情就交给ViewGroup处理了。
onInterceptTouchEvent 的父类返回是false ,所以一般是不会阻断的。
这里我们要特别补充一下滑到事件:滑到事件的组成为--ACTION_DOWN,ACTON_MOVE,ACTION_MOVE...ACTION_MOVE,ACTION_UP组成。
做为ViewGoup。OnInterceptTouchEvent是其第一个处理的函数。
然后呢,我们检测到ACTION_DOWN,然后交由OnInterceptTouchEvent处理,如果是true,则后面的ACTION_MOVE,ACTION_UP交由该VIewGoup的OnTouchEvent处理。
如果OnInterceptTouchEvent对ACTION_DOWN进行拦截,返回true,则交于子VIew处置,同样执行上面的判断,此时ViewGroup的OnInterceptTouchEvent会一直值被调用,用于传递Touch事件给子view。而子view对于滑动事件,先接收了ACTION_DOWN,当检测的手指偏移达到了ACTION_MOVE的滑动标准。此于应进行ev.getAction==MOTIONEVENT.ACTION_MOVE的判断,是的话返回true,进行拦截,此后的滑动事件将不经过该子View的onInterceptTouchEvent事件,全部交由基OnTouchEvent处理。
以下内容转自其它博客:如果在某个层级没有处理ACTION_DOWN事件,那么该层就再也收不到后续的Touch事件了直到下一次ACTION_DOWN事件。
说明:a.某个层级没有处理某个事件指的是它以及它的子View都没有处理该事件。
ViewGroup层处理Touch事件的总体逻辑是:先检测是否需要拦截,没有拦截的话下发给子View处理,如果子View没有处理再自行处理,自行处理的逻辑与View一样。
拦截的逻辑是,将从down到up之间的所有事件看作一组事件,如果从down就拦截了,则组内的后续其它事件完全交给自己处理,不需要再进入拦截逻辑了;如果是从中间拦截,则先给子View发送cancel事件,组内的后续其它事件完全交给自己处理,不需要再进入拦截逻辑了。
分发的逻辑是,在ACTION_DOWN事件的时候,寻找子View进行处理,称为寻找Target;如果没有找到Target,则自行处理;如果找到Target,则交由Target处理。
从代码上看,dispatchTouchEvent负责分发逻辑,onTouchEvent负责真正的处理逻辑,一般应该重载onTouchEvent,只有特殊情况下才需要重载dispatchTouchEvent。
滑动流程:
OnIterceptOnTouchEvent 代号:void1
OnTouchEvent 代号:void2
当手指触摸屏幕时,这时将触发viewgroup的void1方法的ACTION_DOWN方法,返回值为false,
然后触发void1方法的ACTION_MOVE方法,这时会有一个计算判断,当手指的位置发生偏移时,
证明用户想滑动页面,这时return ture,将ACTION_MOVE这个动作传递给void2后续触摸事件将不会触发void1,
而void2根据左边来相应的进行绘图滑动。结束时触发void2的ACTION_UP动作,继而告诉系统触摸事件完成。
中途破坏了滑动事件的特殊情况:
如果一个非ACTION_DOWN事件被父View拦截了,则那些上次处理了ACTION_DOWN事件的子View会收到一个ACTION_CANCEL事件,之后不会再收到任何Touch事件了,即使父View不再拦截后续的Touch事件。