Android Touch事件方法机制

事件分发机制
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流程可以一一处理.
对于滑动冲突情况,很多博客都有将,参照一下这篇博客.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值