众所周知,从安卓1.5到现在的8.0已经经过了10个年头,然而很多人对事件分发有着既清楚又模糊的概念,面试时候说是可以大概说一下的,然后真正写自定义view的时候能熟练用的却不多,如果你对下面几个问题都泯然于心,那也就基本掌握其精髓了
1.onInterceptTouchEvent这方法的返回值对分发有何影响,何时被调用
2.getParent().requestDisallowInterceptTouchEvent();这方法是干嘛的,有可能不生效么
3.onTouchEvent在down,move,up阶段的返回值影响啥
4.onTouchEvent的cancel事件何时被触发?
首先看down事件:
比如当你在屏幕上点击一个textView的时候事件其实是传到activity的dispatchTouchEvent的,然后会传到phonewindow的decoview里,那DecorView其实是viewGroup,每个viewGroup都会调用他的dispatchTouchEvent方法,然后看是否onInterceptTouchEvent的返回值会true,如果是的话就自己处理,当然这个源码里这个返回值是与onInterceptTouchEvent和requestDisallowInterceptTouchEvent这两个相关联的,这里暂不讨论后者
假如在down的时候父view的onInterceptTouchEvent返回为true,那子view还能接收到么?
答案是不能,就是这个cycle内所有的事件都交给父view了,那父view还会调用onInterceptTouchEvent来每次拦截么,其实是不会的,就会一直调用父view的onTouchEvent来处理(这里onTouchEvent先默认都返回true)
那这样的话requestDisallowInterceptTouchEvent方法何时会被调用呢?
答案是永远不会,很简单,这个方法是在子view的ontouchEvent那里调用的,能调用子view的这个方法,首先要分发给子view,然后子 view才可以getparent.requestDisallowInterceptTouchEvent(true)请求父类不拦截,这样就会忽略父类的onInterceptTouchEvent的值,故我们写viewgroup的时候绝对不能在onInterceptTouchEvent的down事件返回true,这样子view完全接受不到事件了
第二种情况,当在down事件,返回false的时候,表明此次的down事件是分发给子view的onTouchEvent的down事件,子view的onTouchEvent的down事件一旦返回false,那表明子view处理不了此次的down,很简单此次事件会重新调父view的onTouchEvent,并以后的事件(move,up)不会调用onInterceptTouchEvent方法进行询问
那一般来说,子view的ontTouchEvent的down是返回true的
那是否这个cycle内的move和up也会给子view呢?
答案是不会的,因为父view要每次在dispatchTouchEvent事件中调用
onInterceptTouchEvent来询问是否要拦截,那既然子view的down事件返回true了,当接收到move事件时,他还是要询问一遍。
其次看move事件
这里分几种情况:
1.当父view的onInterceptTouchEvent返回true的时候,表示此事件的move要自己处理,那既然down返回的是false(是调用子view的ontouchEvent的),此时会发送一个cancel事件给子view(源码中有分发的代码,下篇说)
那如果move事件返回false,会给他的父view处理么
如果此时父view的move也是返回fase(ontouchEvent),这样的情况和down不同,当move事件无论返回true或者false ,都会有自己处理,不会在向上传递(既然down都没问题,move有问题,就不管了)
2.当父view的onInterceptTouchEvent返回false的时候,那很显然,会调用子view的ontouchEvent的move(返回值不受影响)
最后看up事件
up事件其实和move事件是一摸一样的,不受返回值的影响
最后说下请求父类不拦截的那个方法
主要是用在父类的onInterceptTouchEvent方法在move和up事件中返回了true,如果子view在ontouchEvent的down事件中调用了此方法(并返回true),那这个cycle内接下来的move和up事件,都不会调用父类的
onInterceptTouchEvent,默认给子view执行了
所以我们能回答刚开始的几个问题了
1.onInterceptTouchEvent通常是父类在dispatchTouchEvent里调用的方法一般在down时,为了能让子view不拦截此事件,返回false让响应子view的ontouchEvent,一旦此事件给子view处理了,每次的(move,up)
都会调用其方法进行询问,调用过子view的请求父类不拦截的代码除外
2,有可能不生效,因为这个方法是子view调用的,当父view在onInterceptTouchEvent在down时返回true时,子view调用也无效
3.onTouchEvent在down时候返回false,表示处理不了此事件,会抛给父view处理此事件(无论父view拦不拦截),父view处理时也不会调用onInterceptTouchEvent方法
在move和up时候返回false,因为down是true了,在分发的源码里并没有对move和up做处理,所以返回值只影响ontouchEvent也就是dispatchTouchevent,并不会产生事件缺损,这一点很多人都有不同的意见,等下篇分析源码时再说
4.子view的cancel事件
当你的down,move,up事件有一个不是自己执行的,是父view执行的,那就父view就会发一个cancel事件给子view(源码里可以看到)
总的结论就是这样,当然如果想看源码分析的,可以看这篇博客。
事件分发基础篇之源码分析篇