Android View事件分发机制 小记

Android事件分发机制,一直以来只知道onInterceptTouchEvent返回true的时候,表示进行拦截,交给本身View的onTouchEvent处理;如果返回false,表示不进行拦截,交给子View处理。现在花一点事件对事件处理做一些总结。

  第一.研究对象。

         需要研究的对象,我将它分为两类,第一类:ViewGroup,也就是可以包含其他View或者ViewGroup;第二类,View,不能包含其他View。这两类的差别在于ViewGroup,包含dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent方法。而View只包含onTouchEvent方法。(注意我这里说的View和android上定义的View有差别,androi上ViewGroup是继承View的)。

  第二.研究的主要函数。

         研究的函数包括三个:dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent。它们之间的关系可以用伪代码表示:

public boolean dispatchTouchEvent(Motiontion ev){
   boolean consume=false;
   if(onInterceptTouchEvent(ev)){
      consume=onTouchEvent(ev);
   } else{
      consume=child.dispatchTouchEvent(ev);
   }
    return consume;
}

     我的理解:若onInterceptTouchEvent进行拦截了,则返回onTouchEvent(ev)的值;否则交给子View去处理。

第三。几种情况分析。

      接下去,我写了1个Demo进行测试,布局比较简单,父View里头套了一个子View。

      1.若父View的onInterceptTouchEvent中的Down返回true,则子View不会接收到touch事件。

       父View的代码:

  @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        int action = ev.getActionMasked();
        switch (action) {
        case MotionEvent.ACTION_DOWN:

            flag = true;
            Log.e("error", "father_inter_action_down="+flag);
            break;
        case MotionEvent.ACTION_MOVE:

            Log.e("error", "father_inter_action_move");
            break;

        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            Log.e("error", "father_inter_action_cancel");
            break;
        default:
            break;
        }
        return flag;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getActionMasked();
        switch (action) {
        case MotionEvent.ACTION_DOWN:

            touchFlag = true;
            Log.e("error", "father_touch_action_down");
            break;
        case MotionEvent.ACTION_MOVE:

            Log.e("error", "father_touch_action_move");
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:

            Log.e("error", "father_touch_action_cancel");
            break;
        default:
            break;
        }
        return touchFlag;

    }

}

     子View的代码:

public boolean onTouchEvent(MotionEvent event) {
        int action = event.getActionMasked();
        switch (action) {
        case MotionEvent.ACTION_DOWN:

            touchFlag = true;
            Log.e("error", "child_touch_action_down");
            break;
        case MotionEvent.ACTION_MOVE:

            Log.e("error", "child_touch_action_move");
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:

            Log.e("error", "child_touch_action_cancel");
            break;
        default:
            break;
        }
        return touchFlag;

    }

   LOG日志为:

01-04 21:46:36.724: E/error(12032): father_inter_action_down=true
01-04 21:46:36.726: E/error(12032): father_touch_action_down
01-04 21:46:36.759: E/error(12032): father_touch_action_move

……
01-04 21:46:36.776: E/error(12032): father_touch_action_move
01-04 21:46:37.178: E/error(12032): father_touch_action_cancel

   结论:从log中可以看到 子View 没有获得touch事件。

2.若父View的onInterceptTouchEvent中的Down返回false,并且子View中Touch事件返回True。

   代码部分:

          父View中的onInterceptTouchEvent:          

           case MotionEvent.ACTION_DOWN:
            flag = false;
            Log.e("error", "father_inter_action_down="+flag);
            break;


            子View中的TouchEvent返回true。

            LOG日志为:

01-04 21:17:08.974: E/error(30622): father_inter_action_down=false
01-04 21:17:08.975: E/error(30622): child_touch_action_down
01-04 21:17:09.004: E/error(30622): father_inter_action_move
……
01-04 21:17:09.336: E/error(30622): father_inter_action_move
01-04 21:17:09.337: E/error(30622): child_touch_action_move
01-04 21:17:09.350: E/error(30622): father_inter_action_cancel
01-04 21:17:09.351: E/error(30622): child_touch_action_cancel

          结论:从上诉可以看出,父View并不会再调用自己的onTouch方法,但是之后的事件:ACTION_MOVE和ACTION_DOWN都会经过父View的onInterceptTouchEvent方法,由于均未进行拦截。所以这些后续事件都传到了子View中。

3.若父View的onInterceptTouchEvent中的Down返回false,并且子View中Touch事件返回false。

   Log日志为:

01-04 21:18:21.334: E/error(851): father_inter_action_down=false
01-04 21:18:21.335: E/error(851): child_touch_action_down
01-04 21:18:21.335: E/error(851): father_touch_action_down
01-04 21:18:21.368: E/error(851): father_touch_action_move
01-04 21:18:21.384: E/error(851): father_touch_action_move
01-04 21:18:21.401: E/error(851): father_touch_action_move

……
01-04 21:18:21.783: E/error(851): father_touch_action_move
01-04 21:18:21.800: E/error(851): father_touch_action_move
01-04 21:18:21.801: E/error(851): father_touch_action_cancel

结论:从上诉可以看出,子View未消耗该touch事件,则该事件向上进行传递,调用父View的onTouch方法(不调用onInterceptTouchEvent方法),由于父View中的onTouch方法对所有事件都返回了True,表示对所有事件进行消耗。

原文地址:https://www.cnblogs.com/woshidalao/p/5100416.html