一、介绍

Android为触摸事件封装了一个类MotionEvent,其实OnTouchEvent的一个参数就是MotionEvent

MotionEvent中封装了触摸点坐标、点击事件类型等

Android中的View可以放在一个ViewGroup中,这个ViewGroup又放在另一ViewGroup中等等,一层层嵌套起来,同一个触摸事件,View和父ViewGroup都想要处理,我们应该传给谁呢,此时就需要事件拦截机制

二、举例说明

完整的事件流程

  • 现在总经理ViewGroupA接到任务X,于是安排部长ViewGroupB去做,
  • ViewGroupB又把任务X交给底层的员工View来做。
  • 当员工View完成任务后,会向部长ViewGroupB报告,
  • 部长ViewGroupB收到报告,又可以向总经理ViewGroupA报告

这就是一个完整的事件流程

    事件传递顺序:        ViewGroupA    ->    ViewGroupB    ->    ViewC

    事件处理顺序:        ViewC    ->    ViewGroupB    ->    ViewGroupA 

    事件传递返回值:    true:拦截,不继续传递    false:不拦截,继续传递

    事件处理返回值:    true:处理了,不上报       false:处理了,但上报

    其实super.onTouchEvent(event)也是false的效果

Android 异常拦截 android 事件拦截_Android 

事件拦截机制:

一系列打断上面完整事件流程的问题都属于事件拦截机制,如下几种情况:

  • 总经理ViewGroupA接到任务X,发现很简单,于是自己完成,没有交给部长B来做
  • 部长ViewGroupB接到员工的报告,发现不用总经理处理,于是独自处理
  • 员工View完成任务,不想上交任务报告,选择自己处理等

Android 异常拦截 android 事件拦截_事件_02

对于ViewGroupA重写一下三个方法

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e(TAG, "ViewGroupA dispatchTouchEvent " + ev.getAction());
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.e(TAG, "ViewGroupA onInterceptTouchEvent " + ev.getAction());
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e(TAG, "ViewGroupA onTouchEvent " + event.getAction() );
        return super.onTouchEvent(event);
    }

ViewGroupB与ViewGroupA类似

对于ViewC给出一下两个方法

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e(TAG, "ViewC dispatchTouchEvent: " + ev.getAction() );
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e(TAG, "ViewC onTouchEvent: " + event.getAction());
        return super.onTouchEvent(event);
    }

可以看出ViewGroup比View多了一个方法onInterceptTouchEvent,此方法便是事件拦截的核心

Android 异常拦截 android 事件拦截_Android 异常拦截_03

之后我们点击C,会与如下日志:

Android 异常拦截 android 事件拦截_拦截_04

所以可以得出

事件传递顺序:ViewGroupA    ->    ViewGroupB    ->    ViewC

事件处理顺序:ViewC    ->    ViewGroupB    ->    ViewGroupA 

其中

事件传递返回值:    true:拦截,不继续传递    false:不拦截,继续传递

事件处理返回值:    true:处理了,不上报       false:处理了,但上报


整个事件的流程如下:onInterceptTouchEvent是事件的核心处理方法

Android 异常拦截 android 事件拦截_拦截_05

举几个图:

1.ViewGroupA把事件传递拦截下来

总经理A发现任务简单,自己处理,没有安排下属,即让ViewGroupA的onInterceptTouchEvent返回true

日志:

Android 异常拦截 android 事件拦截_事件_06

流程:

Android 异常拦截 android 事件拦截_拦截_07

2.ViewGroupB把事件传递拦截下来

部长B把事件拦截下来,自己处理,即让ViewGroupB的onInterceptTouchEvent返回true

日志:

Android 异常拦截 android 事件拦截_分发_08

流程

Android 异常拦截 android 事件拦截_分发_09

3.ViewC把事件拦截下来

员工最开始要上上级汇报,所以一直返回false,现在让onTouchEvent返回true,自己处理

日志:

Android 异常拦截 android 事件拦截_拦截_10

流程:

Android 异常拦截 android 事件拦截_Android 异常拦截_11

4.ViewGroupB把事件处理结果拦截下来

当员工C把报告上交,部长B发现报告有错误,自己处理,即让ViewGroupB的onTouchEvent返回true

日志:

Android 异常拦截 android 事件拦截_Android 异常拦截_12

流程:

Android 异常拦截 android 事件拦截_分发_13