android touch机制

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/izzxacbbt/article/details/83472277

遵循以下原则

子view优先

父类转发与拦截.

最外层的layout最先收到消息,

只有按下事件决定后续事件序列的判断(其他事件是基于按下事件决定谁有可能受到事件)

dispatchTouchEvent()函数,这个函数在view或viewlayout中都存在,

所有事件流程都在dispatchTouchEvent()中处理,view中的dispatchTouchEvent只能决定自己处不处理,没有拦截机制,然后,在dispatchTouchEvent中决定事件处理的的各种逻辑,我们最重要的是知道事件完全由dispatchTouchEvent来决定流程.

对于ViewGroup来说,我们这样考虑,一个事件来到他这里,他决定以下这些,如果这个事件是down,那么他先看一下属不属于自己的子View管辖范围之内,如果在自己的子view管辖范围之内,那么他会先决定自己要不要阻断这个消息,如果不阻断,那么他会把这个消息发给子view处理,如果子view的dispatchTouchEvent返回true,那么说明子view对这个东西感兴趣,接下来的事件都会发给子View,如果子view有监听接口,那么,会运行监听接口,如果我们的子view的Listener返回true,那么会屏蔽掉后面的onTouchEvent,这是因为源码中

  if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }

            if (!result && onTouchEvent(event)) {
                result = true;
            }

可以看到,如果li.mOnTouchListener.onTouch返回true,那么会导致,result为true,这样的结果就会导致下面的一个判断不会进入,这也就是为什么onTouch如果返回true,后面的onClick就不会触发,网上大部分说法都是"消费"了这个事件,背后的原因就是这个.

继续说道ViewGroup的dispatchTouchEvent,如果来一个事件不是down,那么dispatchTouchEvent先判断原来的down事件是否有属下监听(即,其下属的view的dispatchTouchEvent在上一个down事件是否返回了true),如果有这样的下属子view,那么他自己仍旧会决定要不要阻断,如果决定不阻断,则把消息发给属下,比如一个移动消息,不管属下返回true或false,剩下的消息都是发给子view,ViewGroup不会再在onTouchEvent中进行处理,但是ViewGroup可以对这个消息决定要不要拦截,这个拦截只是针对这个特定的Event,如果拦截,则子view不会受到这个消息.

一个非常完备的信息处理机制通过上面的流程即可实现,假如,我们要实现一个listview item左滑的东西,那么我们怎么实现呢?

一般的,一个listview可以设置的监听有,整个listview的滑动监听,每个item的点击监听,listview本身的touch监听,并没有单个listitem的滑动监听,所以我们如果自己设置listitem的滑动监听,那就会出现一个问题,因为如果我们滑动的是item,那么事件会被放到item中,而作为listview则不会处理自己需要的上下滑动事件,所以会出现这种奇怪的问题,那么怎么解决呢?解决方法当然是非常之多,

比如我们可以在listview中先判断,如果是上下滑动的事件就拦截,否则就交给下属处理,这样就完成了区分

又或者你可以让子view来调用viewGroup的onTouchEvent,比如在子view中声明一个他的容器viewgroup的成员变量,设置这个成员变量为他的容器,然后在子view中经过判断,判断这个事件是不是上下滑动,如果是,则调用父类容器的onTouchEvent来处理,这也是一种简单的实现方法,而且没有用到拦截函数.

接下来做一个实验

A是最外层的容器,B是A里面的容器,C是B里面的容器.


//以下这些度很好理解,就是正常的流程,由于我们知道默认的是都不监听,所以只有按下事件能有输出,因为其他事件都被无视了,只要按下事件没有任何反应,其他事件都被无视.
Touch  A                -----------------------------------No Change
                I/LinearLayout: dispatchTouchEvent
                onInterceptTouchEvent
                onTouchEvent


Touch B                  ----------------------------------No Change
I/LinearLayout: dispatchTouchEvent
                onInterceptTouchEvent
I/FrameLayout: dispatchTouchEvent
               onInterceptTouchEvent
               onTouchEvent
I/LinearLayout: onTouchEvent

Touch C                 ----------------------------------No Change
I/LinearLayout: dispatchTouchEvent
                onInterceptTouchEvent
I/FrameLayout: dispatchTouchEvent
               onInterceptTouchEvent
I/MyView: dispatchtouchevent
          onTouchEvent
I/FrameLayout: onTouchEvent
I/LinearLayout: onTouchEvent

----总结:无


//接下来探寻dispatchtouchevent的返回值作用  


//A的dispatchtouchevent返回true

Touch A               ----------------------------------抬起与按下都有反应,且抬起时不再调用onInterceptTouchEvent
10-28 08:07:27.702 6465-6465/com.example.administrator.touch_test I/LinearLayout: dispatchTouchEvent
    onInterceptTouchEvent
    onTouchEvent
10-28 08:07:28.988 6465-6465/com.example.administrator.touch_test I/LinearLayout: dispatchTouchEvent
    onTouchEvent

Touch B               ----------------------------------抬起按下都有反应,且抬起时不再把消息发送给B,且不再调用阻断函数
10-28 08:10:41.919 6465-6465/com.example.administrator.touch_test I/LinearLayout: dispatchTouchEvent
10-28 08:10:41.920 6465-6465/com.example.administrator.touch_test I/LinearLayout: onInterceptTouchEvent
10-28 08:10:41.920 6465-6465/com.example.administrator.touch_test I/FrameLayout: dispatchTouchEvent
    onInterceptTouchEvent
    onTouchEvent
10-28 08:10:41.920 6465-6465/com.example.administrator.touch_test I/LinearLayout: onTouchEvent
10-28 08:10:41.989 6465-6465/com.example.administrator.touch_test I/LinearLayout: dispatchTouchEvent
10-28 08:10:41.990 6465-6465/com.example.administrator.touch_test I/LinearLayout: onTouchEvent

Touch B              -----------------------------------测试如果B的onTouchEvent有反应,是否会把抬起消息发送----结果:如果子view的onTouchEvent有反应,则抬起时会发送消息,且仍旧会调用interceptTouchEvent保证不丢失监管权.

10-28 08:13:26.556 6465-6465/com.example.administrator.touch_test I/LinearLayout: dispatchTouchEvent
    onInterceptTouchEvent
10-28 08:13:26.556 6465-6465/com.example.administrator.touch_test I/FrameLayout: dispatchTouchEvent
    onInterceptTouchEvent
    onTouchEvent
10-28 08:13:26.598 6465-6465/com.example.administrator.touch_test I/LinearLayout: dispatchTouchEvent
    onInterceptTouchEvent
10-28 08:13:26.598 6465-6465/com.example.administrator.touch_test I/FrameLayout: dispatchTouchEvent
    onTouchEvent

Touch B             -----------------------------------这次测试如果onTouchEvent不反应,但是B的dispatchtouchevent也返回true是否和上次一样----可以看到的确一样,说明dispatchtouchevent的确可以起到和onTouchEvent一样的效果,代表他想监管这次的消息序列

10-28 08:21:31.971 6465-6465/com.example.administrator.touch_test I/LinearLayout: dispatchTouchEvent
    onInterceptTouchEvent
10-28 08:21:31.971 6465-6465/com.example.administrator.touch_test I/FrameLayout: dispatchTouchEvent
    onInterceptTouchEvent
    onTouchEvent
10-28 08:21:32.026 6465-6465/com.example.administrator.touch_test I/LinearLayout: dispatchTouchEvent
    onInterceptTouchEvent
10-28 08:21:32.026 6465-6465/com.example.administrator.touch_test I/FrameLayout: dispatchTouchEvent
    onTouchEvent


//A的dispatchtouchevent保留原样,B onTouchEvent return true  

Touch B                 ------------------
10-28 08:42:50.086 6465-6465/com.example.administrator.touch_test I/LinearLayout: dispatchTouchEvent
    onInterceptTouchEvent
    onTouchEvent
10-28 08:42:51.820 6465-6465/com.example.administrator.touch_test I/LinearLayout: dispatchTouchEvent
    onInterceptTouchEvent
10-28 08:42:51.820 6465-6465/com.example.administrator.touch_test I/FrameLayout: dispatchTouchEvent
    onInterceptTouchEvent
    onTouchEvent
10-28 08:42:51.886 6465-6465/com.example.administrator.touch_test I/LinearLayout: dispatchTouchEvent
10-28 08:42:51.887 6465-6465/com.example.administrator.touch_test I/LinearLayout: onInterceptTouchEvent
10-28 08:42:51.887 6465-6465/com.example.administrator.touch_test I/FrameLayout: dispatchTouchEvent
    onTouchEvent

Touch B                 ------------------B ontouch return false  dispatch  return true可以看到和上面完全一样,也就证实了我们的猜想
10-28 08:47:45.385 6465-6465/com.example.administrator.touch_test I/LinearLayout: dispatchTouchEvent
    onInterceptTouchEvent
    onTouchEvent
10-28 08:47:50.438 6465-6465/com.example.administrator.touch_test I/LinearLayout: dispatchTouchEvent
    onInterceptTouchEvent
10-28 08:47:50.438 6465-6465/com.example.administrator.touch_test I/FrameLayout: dispatchTouchEvent
    onInterceptTouchEvent
    onTouchEvent
10-28 08:47:50.501 6465-6465/com.example.administrator.touch_test I/LinearLayout: dispatchTouchEvent
    onInterceptTouchEvent
10-28 08:47:50.501 6465-6465/com.example.administrator.touch_test I/FrameLayout: dispatchTouchEvent
    onTouchEvent

再看我们在上面提出的实现listview滑动区分的第二种方法

这里是容器B的onTouchEvent,对move进行输出

   public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        Log.e(str, "onTouchEvent");
        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:
                Log.e(str, "----------------Frame Move------------------------");
        }
        return false;
//        return true;
    }

这里是buttonC的onTouchEvent,他不处理move,而是调用容器B的也就是这里mpf(FrameLayout)的onTouchEvent

  public boolean onTouchEvent(MotionEvent event) {

        Log.e(str, "onTouchEvent");
        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:
                Log.e(str, "Move return false");
                mpf.onTouchEvent(event);
                return false;
            case MotionEvent.ACTION_DOWN:
                Log.e(str, "down return true");
                return true;


        }
        return false;
//        return true;
    }

我们来看输出

12-06 13:18:01.431 13292-13292/com.example.administrator.touch_test E/LinearLayout: dispatchTouchEvent
    onInterceptTouchEvent
12-06 13:18:01.432 13292-13292/com.example.administrator.touch_test E/FrameLayout: dispatchTouchEvent
    onInterceptTouchEvent
12-06 13:18:01.432 13292-13292/com.example.administrator.touch_test E/MyView: dispatchtouchevent
    onTouchEvent
    Move return false
12-06 13:18:01.432 13292-13292/com.example.administrator.touch_test E/FrameLayout: onTouchEvent
    ----------------Frame Move------------------------
12-06 13:18:01.449 13292-13292/com.example.administrator.touch_test E/LinearLayout: dispatchTouchEvent
    onInterceptTouchEvent
12-06 13:18:01.449 13292-13292/com.example.administrator.touch_test E/FrameLayout: dispatchTouchEvent
    onInterceptTouchEvent
12-06 13:18:01.450 13292-13292/com.example.administrator.touch_test E/MyView: dispatchtouchevent
    onTouchEvent
    Move return false
12-06 13:18:01.450 13292-13292/com.example.administrator.touch_test E/FrameLayout: onTouchEvent
    ----------------Frame Move------------------------

可以看到输出符合预期

 
 
 

猜你喜欢

转载自blog.csdn.net/izzxacbbt/article/details/83472277