Android Touch事件方法机制

来源:互联网 发布:银河证券股票交易软件 编辑:程序博客网 时间:2024/05/26 17:48

事件分发机制
Android的事件方法遵循一定的流程,即方法,拦截,消费.分别对应于以下方法:

dispatchTouchEvent: 分发事件onInterceptTouchEvent:拦截事件onTouchEvent:消费事件

能够响应这些方法的有ViewGroup,View,Activity.

Touch流程类别

Touch事件流程有两种一种是down,另外是move,up,这两种事件的分发机制有一定的区别.
Touch事件为什么有两种?我们可以看一下源码.

一.看ViewGroup对事件的分类处理

@Override    public boolean dispatchTouchEvent(MotionEvent ev) {        if (mInputEventConsistencyVerifier != null) {            mInputEventConsistencyVerifier.onTouchEvent(ev, 1);        }        ..........        ..........        //看这段代码, DOWN事件时,满足一定的条件才会走拦截    onInterceptTouchEvent        // Check for interception.         final boolean intercepted;         if (actionMasked == MotionEvent.ACTION_DOWN                 || mFirstTouchTarget != null) {             final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;             if (!disallowIntercept) {                 intercepted = onInterceptTouchEvent(ev);                 ev.setAction(action); // restore action in case it was changed             } else {                 intercepted = false;             }         } else {             // There are no touch targets and this action is not an initial down             // so this view group continues to intercept touches.             intercepted = true;         }        ..........................        //经过一系列的逻辑判断,走dispatchTransformedTouchEvent         .....................       dispatchTransformedTouchEvent {            ............            //最后走到孩子的dispatchTouchEvent             handled = child.dispatchTouchEvent(transformedEvent);       }           }

上面 代码在mGroupFlags & FLAG_DISALLOW_INTERCEPT为false才会走拦截事件,如果为true就会走孩子的diapatchTouchEvent,那我们”ctrl+f”看mGroupFlags & FLAG_DISALLOW_INTERCEPT什么时候会被赋值:

只在一个地方找到

 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {        if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {            // We're already in this state, assume our ancestors are too            return;        }        if (disallowIntercept) {            mGroupFlags |= FLAG_DISALLOW_INTERCEPT;        } else {            mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;        }        // Pass it up to our parent        if (mParent != null) {            mParent.requestDisallowInterceptTouchEvent(disallowIntercept);        }    }

上面的代码大概就是disallowIntercept为true就会修改标记值,请求父容器不要拦截,所以move事件会首先走到孩子的diapatchTiuchevent.

看Activity的处理

Activity实现了Window.Callback借口,复写dispatchTouchEvent,

    /**     * Called to process touch screen events.  You can override this to     * intercept all touch screen events before they are dispatched to the     * window.  Be sure to call this implementation for touch screen events     * that should be handled normally.     *     * @param ev The touch screen event.     *     * @return boolean Return true if this event was consumed.     */    public boolean dispatchTouchEvent(MotionEvent ev) {        // 对down事件做单独的处理        if (ev.getAction() == MotionEvent.ACTION_DOWN) {            onUserInteraction();        }        if (getWindow().superDispatchTouchEvent(ev)) {            return true;        }        return onTouchEvent(ev);    }public boolean onTouchEvent(MotionEvent event) {        if (mWindow.shouldCloseOnTouch(this, event)) {            finish();            return true;        }        return false;    }

从上面的代码看到,Activity的dispatchTouchEvent对down事件做了处理,通过调用onUserInteraction(),将down事件交给自己来处理.move和up交给onTouchEvent来消费(Activity不存在View的嵌套,就不会有拦截方法了).

上面的源码总算的Touch事件的分类说清楚了,下面我们就讲一讲这两类事件的流程.

move,up事件

1.dispatchTouchEvent: 分发事件    1.1--true不分发        触摸事件结束    1.2--false分发        ----2.onInterceptTouchEvent                2.2----true拦截                    ----3.onTouchEvent:消费事件                            3.1----true自己消费,走自己的触摸逻辑                            3.2----false自己不消费,触摸结束                2.2----false不拦截,事件来到子View                    ----diapatchTv                        ----true不分发.走3                        ----false分发,走自己的onInterceptTouchEvent..

总结:

    move,up事件总是遵循上面的流程,对于嵌套的View,父View总是最先接收到触摸事件,子View最先响应事件(因为dispatchTouchEvent,onInterceptTouchEvent默认返回false).

down事件

对于down事件,流程与move,up有点不一样.google对down事件做了特别的处理,事件总是会先走到子View的diapatchTouchEvent.流程如下:

1.dispatchTouchEvent: 分发事件    if(满足一定的条件) {        走子View的dispatchTouchEvent...    }else{        正常的move,up...    }

满足的条件即子View对父容器的要求,即通过调用requestDisallowInterceptTouchEvent,设置几个标记,让父容器走拦截还是将down事件传给子View.

总结:

    对于down事件,子VIew可以通过requestDisallowInterceptTouchEvent来获取事件的处理.google通过提供这个接口,防止父容器把事件给拦截了,让子View在需要时不能处理这个事件.

滑动冲突

在多层嵌套的view当中(如ViewPager与ViewPager,ScroolView与ViewPager……),经常会出现滑动的冲突,主要对Touch事件的流程比较清楚.在什么时候让父容器响应,什么时候让子View处理,通过Touch流程可以一一处理.
对于滑动冲突情况,很多博客都有将,参照一下这篇博客.

0 0
原创粉丝点击