一、触摸反馈基本知识:
对屏幕的一次触摸动作一般可以由为down、up、move三种基本操作组成。
一次触摸生成一系列动作对象,每个对象信息包含在MotionEvent类里进行传递,MotionEvent保存了动作类型、点击位置等等信息。
这一系列的动作对象,一般由down开始,up或cancel结束,中间可以有0到无数个move动作。(cancel用于非人为的提前结束动作的传递)
 
处理触摸反馈的最核心的方法是View.onTouchEvent()。 一个动作对象传递到View.onTouchEvent()方法里处理接下去应该做什么,比如button的点击down动作传入到它的onTouchEvent方法里后改变它的背景色表示被按下了,等up传来时候可以恢复它的背景了,同时触发clickListener方法。
如果想自己处理触摸反馈,用自己的算法逻辑,那么重写这个onTouchEvent方法就好。
 
二、核心事件分发:
为了解决触摸事件冲突的机制。父View和他的子View之间,一般的常规操作是点击在子View上时,触发子View的点击事件,但不触发父View的。点击在没有被子View遮盖的区域时,才会触发父View的点击事件。所以这个机制很好得分配动作的传递处理。
 
怎么个传递法:
一个MotionEvent动作事件会从最上层的view开始向父View一层层调用onTouchEvent()方法。
如果传递到的onTouchEvent()方法没反应,那么会返回false,继续向下传递。
如果有反应,那么返回true,表示消耗此动作事件流,不再向下传递到其他父View的onTouchEvent方法里。
那么一旦返回true的时候,down后面的事件都会传递到这个view的onTouchEvent方法里处理。up和move的返回值不会影响事件的传递,为了方便可全设成true
 
demo :ViewGroupA 包含ViewGroupB,ViewGroupB包含ViewC。
 
 
默认情况(onTouchEvent返回false)点击C区域的log打印如图,且只传递处理了Down事件,该点击中的Up事件不会再处理了:
图1
【回忆知识点】点击触摸事件/touch事件传递
 
然后更换ViewC的onTouchEvent返回值为true时,Down动作的log如下,显示不会调用B和A的onTouchEvent,且一样的流程处理up事件:
图2
【回忆知识点】点击触摸事件/touch事件传递
 
 
三、拦截机制:
 
在动作事件到达onTouchEvent方法前,先从根布局开始向上一层层询问是否拦截这个事件,方法便是 onInterceptTouchEvent(),只有ViewGroup有此方法,View不会有。
返回false不拦截,就上层传递调用onInterceptTouchEvent,一遍询问完了之后才会进行调用onTouchEvent。
看图1中可以看出从ViewGroupA到ViewGroupB遍历完onInterceptTouchEvent方法后,因为全返回false,于是再从ViewC调用onTouvhEvent。
那么设B的 onInterceptTouchEvent返回true时 效果如何?
看下demo里先设b的onInterceptTouchEvent 返回true。看图3日志
图3
【回忆知识点】点击触摸事件/touch事件传递
日志说明B拦截方法返回true时直接调用B的onTouchEvent。
被拦截后 后续的事件经过A的拦截方法直接到B的onTouchEvent。(demo待定)
 
 
onTouchEvent和onInterceptEvent的一点区别在于onTouchEvent对事件消费由down事件决定:
     down事件在onTouchEvent里返回true时,后续事件的返回值便不会再影响其他事件消费,全传入该View的onTouchEvent
    onInterceptEvent不管它的返回值如何,不会影响自己和其他onIntercept对整个事件流的监听。只有触发到需要
 
 
 
【回忆知识点】点击触摸事件/touch事件传递布局包含关系 :父布局A-父布局B-子ViewC
分别点击viewC区域后的log(clickable为true时该View的onTouchEvent返回为true)
1: 默认情况。只传递一次ActionDown
【回忆知识点】点击触摸事件/touch事件传递
2:ViewC的ViewC的onTouchEvent返回true时
【回忆知识点】点击触摸事件/touch事件传递 
3:ViewGroupB的onTouchEvent返回true时
【回忆知识点】点击触摸事件/touch事件传递
 

相关文章: