ViewGroup的TouchEvent的处理机制

来源:互联网 发布:linq 更新数据 编辑:程序博客网 时间:2024/06/08 12:33

触摸事件TouchEvent的传递路径:

Activity->Window->DecorView(DecorView即为一个ViewGroup)

ViewGroup中的dispatchTouchEvent源码

/* * * ViewGroup的dispatchTouchEvent中判断是否拦截事件部分逻辑代码 */ if (actionMasked == MotionEvent.ACTION_DOWN) {      // 当接收到DOWN事件时,会执行重置FLAG_DISALLOW_INTERCEPT标记位, mFirstTouchTarget = null等操作      cancelAndClearTouchTargets(ev);      resetTouchState();}// 判断是否拦截事件的实现逻辑final boolean intercepted;// 传入的为Down事件时ViewGourp一定会执行onInterceptTouchEvent(ev)方法询问是否需要拦截该Down事件// 传入的事件不为Down时, ViewGroup会判断当前事件序列的前一事件是否被子View消耗了, 若有子View消耗(即mFirstTouchTarget != null), 也有可能触发ViewGroup拦截该事件if (actionMasked == MotionEvent.ACTION_DOWN     || mFirstTouchTarget != null) {        // 若当前为Down事件时, FLAG_DISALLOW_INTERCEPT会被重置, 所以一定会执行if下中的语句        // 该标记位是子View在处理事件时通过parent.requestDisallowInterceptTouchEvent()设定, 用于阻止它的parent拦截下一个非Down事件        final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;     if (!disallowIntercept) {          intercepted = onInterceptTouchEvent(ev);          ev.setAction(action); // restore action in case it was changed     } else {          // 如果不允许拦截, 则直接返回false, 将事件分发给子View          intercepted = false;     }} else {     // 当传入的非Down事件 且 mFirstTouchTarget == null时ViewGoup将直接拦截该事件, 交由onTouchEvent()去处理, 若onTouchEvent()也为false则, 将事件抛给上级处理     intercepted = true;}

从源码中可以看出 , 当且仅当传入事件为down或当前序事件已被childView消耗(mFirstTouchTarget != null)时才有可能调用onInterceptTouchEvent()方法

(1) 同一个事件序列是从手指接触屏幕的那一刻起, 到手指离开屏幕的那一刻结束, 在这个过程中所产生的一系列事件, 这个事件序列以down事件开始, 中间含有数量不等的move事件, 最终以up事件结束。

(2)ViewGroup默认不拦截任何事件。

(3)View的onTouchEvent默认消耗事件(返回true),除非它是不可点击的(clickable和longClickable同时为false)。

(4)一般down事件都是由点击事件链中最底层的View消耗的。

(5)正常情况下, 一个事件序列(除了down外)只能被一个View消耗。
我们自定义View中一般ViewGroup是不拦截down事件的,当down之后的事件(move、up)传入该ViewGroup时,因为mFirstTouchTarget !=null(指向之前消耗down事件的child),故该ViewGroup会通过onInterceptTouchEvent()进行判断是否拦截该事件。若拦截,则该事件被当前ViewGroup消耗,此时mFirstTouchTarget ==null。当下一个事件传入时 if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null)不成立 ,所以后续事件将不通过onInterceptTouchEvent()判断,直接被拦截该ViewGroup拦截。
特殊情况:我们重写ViewGroup的dispatchTouchEvent时, 在down事件传入时调用
parent.requestDisallowInterceptTouchEvent(true),阻止其父容器拦截move和up事件, 然后在move传入该ViewGroup时某一条件下调用parent.requestDisallowInterceptTouchEvent(false), 此时后续事件可能被父容器拦截,不再传入该ViewGroup。

原创粉丝点击