Android事件派发机制示例初探

前言

Android的事件派发机制原理是开发者必须了解的基础知识,不过以前的学习都只是通过学习别人的博客总结,总是觉得有些明白又总是说不太明白,这里就来通过简单的示例学习事件派发内部的执行过程。

Activity派发源码

Android Activity是展示界面的重要部件,不过它本身也是Context上下文对象,Android系统在接收了用户的触摸事件之后会通过Binder进程间通信将事件传递给Activity。

// Activity
public boolean dispatchTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        onUserInteraction();
    }
    if (getWindow().superDispatchTouchEvent(ev)) {
        return true;
    }
    return onTouchEvent(ev);
}

Activity在接收到触摸事件后后向Window对象查询它是否会消费此触摸事件,如果Window没有消费就返回false由Activity的onTouchEvent处理触摸事件;否则Window消费了就直接返回,不再传递给Activity的onTouchEvent。

// PhoneWindow
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
    return mDecor.superDispatchTouchEvent(event);
}

// DecorView   
public boolean superDispatchTouchEvent(MotionEvent event) {
    return super.dispatchTouchEvent(event);
}

在Android目前只有PhoneWindow这种类型的Window,它内部调用了DecorView,最后DecorView调用了ViewGroup的dispatchTouchEvent,而且ViewGroup其实是继承自View类。

添加测试Demo

通过上面的代码查看可知Android事件派发机制主要涉及到三个类和它们对应的回调方法,第一个类就是Activity类,为了监视它的回调方法,为它和事件派发相关的方法添加日志。

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
    Log.d(TAG, CLASS + " dispatchTouchEvent() event = " + EventHelper.parse(event.getActionMasked()));
    boolean result = super.dispatchTouchEvent(event);
    Log.d(TAG, CLASS + " dispatchTouchEvent() result = " + result);
    return result;
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    Log.d(TAG, CLASS + " onTouchEvent() event = " + EventHelper.parse(event.getActionMasked()));
    boolean result = super.onTouchEvent(event);
    Log.d(TAG, CLASS + " onTouchEvent() result = " + result);
    return result;
}

接下来是ViewGroup方法,这里采用自定义简单的MyViewGroup对象来添加ViewGroup事件派发相关的回调日志。

public class MyViewGroup extends ViewGroup {
    private static final String TAG = "TouchEventTest";
    private static final String CLASS = "MyViewGroup";
    public MyViewGroup(Context context) {
        this(context, null);
    }

    public MyViewGroup(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.d(TAG, CLASS + " onTouch() event = " + EventHelper.parse(event.getActionMasked()));
                boolean result = false;
                Log.d(TAG, CLASS + " onTouch() result = " + result);
                return false;
            }
        });
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (changed) {
            for (int i = 0; i < getChildCount(); i++) {
                View view = getChildAt(i);
                view.layout(100, 100, 100 + view.getMeasuredWidth(), 100 + view.getMeasuredHeight());
            }
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        Log.d(TAG, CLASS + " onInterceptTouchEvent() event = " + EventHelper.parse(event.getActionMasked()));
        boolean result = super.onInterceptTouchEvent(event);
        Log.d(TAG, CLASS + " onInterceptTouchEvent() result = " + result);
        return result;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.d(TAG, CLASS + " dispatchTouchEvent() event = " + EventHelper.parse(event.getActionMasked()));
        boolean result = super.dispatchTouchEvent(event);
        Log.d(TAG, CLASS + " dispatchTouchEvent() result = " + result);
        return result;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG, CLASS + " onTouchEvent() event = " + EventHelper.parse(event.getActionMasked()));
        boolean result = super.onTouchEvent(event);
        Log.d(TAG, CLASS + " onTouchEvent() result = " + result);
        return result;
    }
}

最后是View对象,为了监视它和事件派发相关的逻辑需要继承View对象并且在它的事件派发方法里添加日志。

public class MyView extends View {
    private static final String TAG = "TouchEventTest";
    private static final String CLASS = "MyView";
    private Paint mPaint;

    public MyView(Context context) {
        this(context, null);
    }

    public MyView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint = new Paint();
        mPaint.setColor(getResources().getColor(R.color.colorPrimary));
        mPaint.setTextSize(50);
        setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.d(TAG, CLASS + " onTouch() event = " + EventHelper.parse(event.getActionMasked()));
                boolean result = false;
                Log.d(TAG, CLASS + " onTouch() result = " + result);
                return false;
            }
        });
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.d(TAG, CLASS + " dispatchTouchEvent() event = " + EventHelper.parse(event.getActionMasked()));
        boolean result = super.dispatchTouchEvent(event);
        Log.d(TAG, CLASS + " dispatchTouchEvent() result = " + result);
        return result;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawText("我是子视图", 10, 150, mPaint);
        mPaint.setStrokeWidth(6);
        mPaint.setStyle(Paint.Style.STROKE);
        canvas.drawRect(0, 0, 300, 300, mPaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG, CLASS + " onTouchEvent() event = " + EventHelper.parse(event.getActionMasked()));
        boolean result = super.onTouchEvent(event);
        Log.d(TAG, CLASS + " onTouchEvent() result = " + result);
        return result;
    }
}

通过上面的示例代码可以看出:Activity事件回调包括dispatchTouchEvent和onTouchEvent两个方法,ViewGroup包含dispatchTouchEvent、onInterceptTouchEvent、setOnTouchListener和onTouchEvent四个方法,最后是View包含dispatchTouchEvent、setOnTouchListener和onTouchEvent三个方法。
需要注意的是setOnTouchListener方法设置了监听器对象,它会在事件派发过程中被调用,该方法本身并不参与事件派发过程;其他的方法都有boolean类型的返回值,boolean为true代表事件被消费,boolean为false代表不消费当前事件。

<com.example.misc.widget.MyViewGroup
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".EventActivity">

    <com.example.misc.widget.MyView
        android:layout_width="100dp"
        android:layout_height="100dp" />

</com.example.misc.widget.MyViewGroup>

最后将这两个自定义的组件组合起来作为Activity的内容布局,通过在Activity布局中做触摸事件来测试事件派发流程。

执行测试

回调都返回false

首先测试所有的回调相关的事件都返回false的情况,ViewGroup和View在默认情况下都会返回false表示不消费事件,点击最内部的View对象。由于整个测试的日志非常的长,分别是ACTION_DOWN、ACTION_MOVE和ACTION_UP三个事件的序列,可以看出这个三个事件是按照顺序发出,其中ACTION_MOVE可以有多个事件发生,这里就把只展示其中一个ACTION_MOVE。

EventActivity dispatchTouchEvent() event = ACTION_DOWN

    MyViewGroup dispatchTouchEvent() event = ACTION_DOWN
    MyViewGroup onInterceptTouchEvent() event = ACTION_DOWN
    MyViewGroup onInterceptTouchEvent() result = false

        MyView dispatchTouchEvent() event = ACTION_DOWN
        MyView onTouch() event = ACTION_DOWN
        MyView onTouch() result = false
        MyView onTouchEvent() event = ACTION_DOWN
        MyView onTouchEvent() result = false
        MyView dispatchTouchEvent() result = false

    MyViewGroup onTouch() event = ACTION_DOWN
    MyViewGroup onTouch() result = false
    MyViewGroup onTouchEvent() event = ACTION_DOWN
    MyViewGroup onTouchEvent() result = false
    MyViewGroup dispatchTouchEvent() result = false

EventActivity onTouchEvent() event = ACTION_DOWN
EventActivity onTouchEvent() result = false
EventActivity dispatchTouchEvent() result = false

// ACTION_MOVE
EventActivity dispatchTouchEvent() event = ACTION_MOVE
EventActivity onTouchEvent() event = ACTION_MOVE
EventActivity onTouchEvent() result = false
EventActivity dispatchTouchEvent() result = false

// ACTION_UP
EventActivity dispatchTouchEvent() event = ACTION_UP
EventActivity onTouchEvent() event = ACTION_UP
EventActivity onTouchEvent() result = false
EventActivity dispatchTouchEvent() result = false

从ACTION_DOWN事件执行打印日志可以清楚的看出各个回调方法执行的顺序,单个对象的内部执行顺序可以归纳成dispatchTouchEvent -> (onInterceptTouchEvent) -> (onTouch) -> onTouchEvent,其中onInterceptTouchEvent只有ViewGroup类型有这个方法,Activity没有onTouch方法。对象之间的调用顺序是dispatchTouchEvent调用内部会询问ViewGroup对象是否消费,ViewGroup的dispatchTouchEvent内部询问View是否消费,不消费容器对象才会自己决定是否消费。后面的ACTION_MOVE和ACTION_UP由于在ACTION_DOWN阶段ViewGroup已经决定不消费事件序列,后续的事件都没有再发送给ViewGroup。

ViewGroup onInterceptTouchEvent返回true

接下来再修改ViewGroup的onInterceptTouchEvent返回为true,其他方法的返回值依然是false,查看事件执行打印的序列。

// ACTION_DOWN
EventActivity dispatchTouchEvent() event = ACTION_DOWN

    MyViewGroup dispatchTouchEvent() event = ACTION_DOWN
    MyViewGroup onInterceptTouchEvent() event = ACTION_DOWN
    MyViewGroup onInterceptTouchEvent() result = true
    MyViewGroup onTouch() event = ACTION_DOWN
    MyViewGroup onTouch() result = false
    MyViewGroup onTouchEvent() event = ACTION_DOWN
    MyViewGroup onTouchEvent() result = false
    MyViewGroup dispatchTouchEvent() result = false

EventActivity onTouchEvent() event = ACTION_DOWN
EventActivity onTouchEvent() result = false
EventActivity dispatchTouchEvent() result = false

// ACTION_MOVE
EventActivity dispatchTouchEvent() event = ACTION_MOVE
EventActivity onTouchEvent() event = ACTION_MOVE
EventActivity onTouchEvent() result = false
EventActivity dispatchTouchEvent() result = false

// ACTION_UP
EventActivity dispatchTouchEvent() event = ACTION_UP
EventActivity onTouchEvent() event = ACTION_UP
EventActivity onTouchEvent() result = false
EventActivity dispatchTouchEvent() result = false

可以看到只有onInterceptTouchEvent返回true的情况下,触摸事件只有ACTION_DOWN被传到了ViewGroup,之后由于ViewGroup的dispatchTouchEvent返回了false,ACTION_MOVE和ACTION_UP都没有再传递给ViewGroup了。

ViewGroup onTouch返回true

接下来修改ViewGroup内部的onTouch返回为true代表ViewGroup会在setOnTouchEvent的事件回调中消费此事件,同时onInterceptTouchEvent返回false。查看打印的日志结果,其中ACTION_MOVE多个事件都是一致的序列这里只列出第一个ACTION_MOVE。

// ACTION_DOWN
EventActivity dispatchTouchEvent() event = ACTION_DOWN

    MyViewGroup dispatchTouchEvent() event = ACTION_DOWN
    MyViewGroup onInterceptTouchEvent() event = ACTION_DOWN
    MyViewGroup onInterceptTouchEvent() result = false

        MyView dispatchTouchEvent() event = ACTION_DOWN
        MyView onTouch() event = ACTION_DOWN
        MyView onTouch() result = false
        MyView onTouchEvent() event = ACTION_DOWN
        MyView onTouchEvent() result = false
        MyView dispatchTouchEvent() result = false

    MyViewGroup onTouch() event = ACTION_DOWN
    MyViewGroup onTouch() result = true
    MyViewGroup dispatchTouchEvent() result = true

EventActivity dispatchTouchEvent() result = true

// ACTION_MOVE
EventActivity dispatchTouchEvent() event = ACTION_MOVE

    MyViewGroup dispatchTouchEvent() event = ACTION_MOVE
    MyViewGroup onTouch() event = ACTION_MOVE
    MyViewGroup onTouch() result = true
    MyViewGroup dispatchTouchEvent() result = true

EventActivity dispatchTouchEvent() result = true

// ACTION_UP
EventActivity dispatchTouchEvent() event = ACTION_UP

    MyViewGroup dispatchTouchEvent() event = ACTION_UP
    MyViewGroup onTouch() event = ACTION_UP
    MyViewGroup onTouch() result = true
    MyViewGroup dispatchTouchEvent() result = true

EventActivity dispatchTouchEvent() result = true

可以看出在ACTION_DOWN事件开始的时候还是Activity->ViewGroup->View顺序先查询子对象是否消费事件,由于View未消费ACTION_DOWN事件,ViewGroup在onTouch中返回了true,最终ViewGroup和Activity的onTouchEvent都没有被回调,也即是说ACTION_DOWN事件被ViewGroup消费掉了。之后的ACTION_MOVE和ACTION_UP都只执行到了ViewGroup的onTouch,事件没有再继续传递给View对象了。

ViewGroup onTouchEvent返回true

接下来再将ViewGroup的onTouchEvent修改成消费掉事件,将其他方法都设置为false。查看一下事件执行日志,这里去掉了多个相同的ACTION_MOVE序列。

// ACTION_DOWN
EventActivity dispatchTouchEvent() event = ACTION_DOWN

    MyViewGroup dispatchTouchEvent() event = ACTION_DOWN
    MyViewGroup onInterceptTouchEvent() event = ACTION_DOWN
    MyViewGroup onInterceptTouchEvent() result = false

        MyView dispatchTouchEvent() event = ACTION_DOWN
        MyView onTouch() event = ACTION_DOWN
        MyView onTouch() result = false
        MyView onTouchEvent() event = ACTION_DOWN
        MyView onTouchEvent() result = false
        MyView dispatchTouchEvent() result = false

    MyViewGroup onTouch() event = ACTION_DOWN
    MyViewGroup onTouch() result = false
    MyViewGroup onTouchEvent() event = ACTION_DOWN
    MyViewGroup onTouchEvent() result = true
    MyViewGroup dispatchTouchEvent() result = true

EventActivity dispatchTouchEvent() result = true

// ACTION_MOVE
EventActivity dispatchTouchEvent() event = ACTION_MOVE

    MyViewGroup dispatchTouchEvent() event = ACTION_MOVE
    MyViewGroup onTouch() event = ACTION_MOVE
    MyViewGroup onTouch() result = false
    MyViewGroup onTouchEvent() event = ACTION_MOVE
    MyViewGroup onTouchEvent() result = true
    MyViewGroup dispatchTouchEvent() result = true

EventActivity dispatchTouchEvent() result = true

// ACTION_UP
EventActivity dispatchTouchEvent() event = ACTION_UP

    MyViewGroup dispatchTouchEvent() event = ACTION_UP
    MyViewGroup onTouch() event = ACTION_UP
    MyViewGroup onTouch() result = false
    MyViewGroup onTouchEvent() event = ACTION_UP
    MyViewGroup onTouchEvent() result = true
    MyViewGroup dispatchTouchEvent() result = true

EventActivity dispatchTouchEvent() result = true

ACTION_DWON事件一直传递到View查看View是否消费,确定View不消费之后才由ViewGroup决定是否消费,ViewGroup决定消费之后ACTION_MOVE和ACTION_UP都只有ViewGroup获取,不再向View查看是否会消费。

ViewGroup onIterceptTouchEvent和onTouchEvent都返回true

接下来再设置onInterceptTouchEvent返回true,onTouchEvent返回也是true查看调用的事件序列结果。

// ACTION_DOWN
EventActivity dispatchTouchEvent() event = ACTION_DOWN

    MyViewGroup dispatchTouchEvent() event = ACTION_DOWN
    MyViewGroup onInterceptTouchEvent() event = ACTION_DOWN
    MyViewGroup onInterceptTouchEvent() result = true
    MyViewGroup onTouch() event = ACTION_DOWN
    MyViewGroup onTouch() result = false
    MyViewGroup onTouchEvent() event = ACTION_DOWN
    MyViewGroup onTouchEvent() result = true
    MyViewGroup dispatchTouchEvent() result = true

EventActivity dispatchTouchEvent() result = true

// ACTION_MOVE
EventActivity dispatchTouchEvent() event = ACTION_MOVE

    MyViewGroup dispatchTouchEvent() event = ACTION_MOVE
    MyViewGroup onTouch() event = ACTION_MOVE
    MyViewGroup onTouch() result = false
    MyViewGroup onTouchEvent() event = ACTION_MOVE
    MyViewGroup onTouchEvent() result = true
    MyViewGroup dispatchTouchEvent() result = true

EventActivity dispatchTouchEvent() result = true

// ACTION_UP
EventActivity dispatchTouchEvent() event = ACTION_UP

    MyViewGroup dispatchTouchEvent() event = ACTION_UP
    MyViewGroup onTouch() event = ACTION_UP
    MyViewGroup onTouch() result = false
    MyViewGroup onTouchEvent() event = ACTION_UP
    MyViewGroup onTouchEvent() result = true
    MyViewGroup dispatchTouchEvent() result = true

EventActivity dispatchTouchEvent() result = true

ACTION_DOWN事件在onInterceptTouchEvent被截获之后不必在询问子控件是否需要消费当前事件,所有的事件都由ViewGroup负责消费。

View.onTouchEvent返回true

其他全部设置为false,设置View的onTouchEvent返回值为true,查看事件调用序列打印日志。

// ACTION_DOWN
EventActivity dispatchTouchEvent() event = ACTION_DOWN

    MyViewGroup dispatchTouchEvent() event = ACTION_DOWN
    MyViewGroup onInterceptTouchEvent() event = ACTION_DOWN
    MyViewGroup onInterceptTouchEvent() result = false

        MyView dispatchTouchEvent() event = ACTION_DOWN
        MyView onTouch() event = ACTION_DOWN
        MyView onTouch() result = false
        MyView onTouchEvent() event = ACTION_DOWN
        MyView onTouchEvent() result = true
        MyView dispatchTouchEvent() result = true

    MyViewGroup dispatchTouchEvent() result = true

EventActivity dispatchTouchEvent() result = true

// ACTION_MOVE
EventActivity dispatchTouchEvent() event = ACTION_MOVE

    MyViewGroup dispatchTouchEvent() event = ACTION_MOVE
    MyViewGroup onInterceptTouchEvent() event = ACTION_MOVE
    MyViewGroup onInterceptTouchEvent() result = false
    MyView dispatchTouchEvent() event = ACTION_MOVE

        MyView onTouch() event = ACTION_MOVE
        MyView onTouch() result = false
        MyView onTouchEvent() event = ACTION_MOVE
        MyView onTouchEvent() result = true
        MyView dispatchTouchEvent() result = true

    MyViewGroup dispatchTouchEvent() result = true

EventActivity dispatchTouchEvent() result = true

// ACTION_UP
EventActivity dispatchTouchEvent() event = ACTION_UP

    MyViewGroup dispatchTouchEvent() event = ACTION_UP
    MyViewGroup onInterceptTouchEvent() event = ACTION_UP
    MyViewGroup onInterceptTouchEvent() result = false

        MyView dispatchTouchEvent() event = ACTION_UP
        MyView onTouch() event = ACTION_UP
        MyView onTouch() result = false
        MyView onTouchEvent() event = ACTION_UP
        MyView onTouchEvent() result = true
        MyView dispatchTouchEvent() result = true

    MyViewGroup dispatchTouchEvent() result = true

EventActivity dispatchTouchEvent() result = true

事件会从Activity->ViewGroup->View传递最终被View消费掉,以后所有的ACTION_MOVE和ACTION_UP都会只有View消费,Activity和ViewGroup只负责传递事件。

View.onTouchEvent返回true,ViewGroup.onInterceptTouchEvent部分返回true

接下来保留View的onTouchEvent返回为true,同时为ViewGroup的onInterceptTouchEvent添加如下的逻辑,在用户的手指超出一段距离之后就让ViewGroup截获当前触摸事件。

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    Log.d(TAG, CLASS + " onInterceptTouchEvent() event = " + EventHelper.parse(event.getActionMasked()));
    boolean result = super.onInterceptTouchEvent(event);
    int x = (int) event.getX();
    if (x > 200) {
        result = true;
    }
    Log.d(TAG, CLASS + " onInterceptTouchEvent() result = " + result);
    return result;
}

接着查看事件序列的打印日志,这就是子控件获得了触摸事件但是接下来父控件对触摸事件做了截获操作。在截获事件发生之前的事件序列和前面只有View.onTouchEvent返回true的序列一致,从ACTION_CANCEL事件开始截获逻辑。

// ACTION_MOVE事件被转换成了ACTION_CANCEL给View
EventActivity dispatchTouchEvent() event = ACTION_MOVE

    MyViewGroup dispatchTouchEvent() event = ACTION_MOVE
    MyViewGroup onInterceptTouchEvent() event = ACTION_MOVE
    MyViewGroup onInterceptTouchEvent() result = true

        MyView dispatchTouchEvent() event = ACTION_CANCEL
        MyView onTouch() event = ACTION_CANCEL
        MyView onTouch() result = false
        MyView onTouchEvent() event = ACTION_CANCEL
        MyView onTouchEvent() result = true
        MyView dispatchTouchEvent() result = true

    MyViewGroup dispatchTouchEvent() result = true

EventActivity dispatchTouchEvent() result = true

// 剩下的ACTION_MOVE事件
EventActivity dispatchTouchEvent() event = ACTION_MOVE
    MyViewGroup dispatchTouchEvent() event = ACTION_MOVE
    MyViewGroup onTouch() event = ACTION_MOVE
    MyViewGroup onTouch() result = false
    MyViewGroup onTouchEvent() event = ACTION_MOVE
    MyViewGroup onTouchEvent() result = false
    MyViewGroup dispatchTouchEvent() result = false

EventActivity onTouchEvent() event = ACTION_MOVE
EventActivity onTouchEvent() result = false
EventActivity dispatchTouchEvent() result = false


// 最后的ACTION_UP事件
EventActivity dispatchTouchEvent() event = ACTION_UP

    MyViewGroup dispatchTouchEvent() event = ACTION_UP
    MyViewGroup onTouch() event = ACTION_UP
    MyViewGroup onTouch() result = false
    MyViewGroup onTouchEvent() event = ACTION_UP
    MyViewGroup onTouchEvent() result = false
    MyViewGroup dispatchTouchEvent() result = false

EventActivity onTouchEvent() event = ACTION_UP
EventActivity onTouchEvent() result = false
EventActivity dispatchTouchEvent() result = false

可以看到在onInterceptTouchEvent未截获时事件传递给了View,之后有ACTION_MOVE事件发生时发生了截获事件并且将ACTION_MOVE转换成了ACTION_CANCEL传递给View,以后不论ViewGroup是否消费,被截获的事件后续都会传递给ViewGroup处理。

总结

  1. Android事件派发是从Activity -> ViewGroup -> View顺序传递
  2. 事件在每个对象内部的处理顺序dispatchTouchEvent -> (onInterceptTouchEvent ViewGroup特有) -> (onTouch Activity没有) -> onTouchEvent
  3. 事件的序列从ACTION_DOWN -> (ACTION_MOVE)* -> ACTION_UP,星号代表0或无限个
  4. ViewGroup的onInterceptTouchEvent只要返回一次true,之后就不会再被调用了
  5. View和ViewGroup的dispatchTouchEvent返回true代表会接收以后的事件,返回false代表不会在接收之后的事件,除了最后一条特例
  6. 一个事件序列一旦被某个ViewGrou或者View消费之后后续的事件都由它继续消费,除了最后一条特例
  7. 事件在开始被View消费,随后某个情况下ViewGroup通过interceptTouchEvent返回true截获事件,这时ViewGroup会先把截获时产生的ACTION_MOVE变成ACTION_CANCEL传递给View,后面的所有ACTION_MOVE和ACTION_UP都由ViewGroup消费,不管ViewGroup的dispatchTouchEvent返回值是什么

猜你喜欢

转载自blog.csdn.net/xingzhong128/article/details/80098031