View事件分发机制探究

概述

Android开发中,事件分发机制则是不少童靴进步中的的拦路虎。但是必须客观认识View的滑动机制—-非常、特别以及极其重要!像ScrollView嵌套RecyclerView(或者ListView)的滑动冲突问题的理论基础就是事件分发机制。
书本上的也有不错的讲解View事件分发机制的资料,但是大部分都直接从源码角度进行分析,对于刚入门不久的同学们有点晦涩难懂。本文将通过一个三层的View嵌套实例,通过日志来探究View事件分发和拦截机制的具体的工作情况。

事件探究

首先写一个自定义的布局

<eventintercept.ViewGroupA xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/viewGroupA"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#dddd00"
    android:orientation="vertical">

    <eventintercept.ViewGroupB
        android:id="@+id/viewGroupB"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_gravity="center"
        android:gravity="center"
        android:background="#00dddd"
        android:orientation="vertical">

        <eventintercept.ViewC
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:background="#dd00dd" />
    </eventintercept.ViewGroupB>
</eventintercept.ViewGroupA>

大致的图形结果是
View事件分发布局

ViewA是一个自定义的FrameLayout

public class ViewGroupA extends FrameLayout {
    public ViewGroupA(Context context) {
        super(context);
    }

    public ViewGroupA(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

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

    @TargetApi(Build.VERSION_CODES.KITKAT)
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.d("eventInfo--->", this.getClass().getSimpleName() + " onInterceptTouchEvent,action=" + MotionEvent.actionToString(ev.getAction()));
        boolean result = super.onInterceptTouchEvent(ev);
        Log.d("eventInfo--->", this.getClass().getSimpleName() + " onInterceptTouchEvent,result=" + result);
        return result;
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.d("eventInfo--->", this.getClass().getSimpleName() + " dispatchTouchEvent,action=" + MotionEvent.actionToString(ev.getAction()));
        boolean result = super.dispatchTouchEvent(ev);
        Log.d("eventInfo--->", this.getClass().getSimpleName() + " dispatchTouchEvent,result=" + result);
        return result;
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        Log.d("eventInfo--->", this.getClass().getSimpleName() + " onTouchEvent,action=" + MotionEvent.actionToString(ev.getAction()));
        boolean result = super.onTouchEvent(ev);
        Log.d("eventInfo--->", this.getClass().getSimpleName() + " onTouchEvent,result=" + result);
        return result;
    }
}

ViewB是一个自定义的LinearLayout

public class ViewGroupB extends LinearLayout {
    public ViewGroupB(Context context) {
        super(context);
    }

    public ViewGroupB(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

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

    @TargetApi(Build.VERSION_CODES.KITKAT)
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.d("eventInfo--->", this.getClass().getSimpleName() + " onInterceptTouchEvent,action=" + MotionEvent.actionToString(ev.getAction()));
        boolean result = super.onInterceptTouchEvent(ev);
        Log.d("eventInfo--->", this.getClass().getSimpleName() + " onInterceptTouchEvent,result=" + result);
        return result;
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.d("eventInfo--->", this.getClass().getSimpleName() + " dispatchTouchEvent,action=" + MotionEvent.actionToString(ev.getAction()));
        boolean result = super.dispatchTouchEvent(ev);
        Log.d("eventInfo--->", this.getClass().getSimpleName() + " dispatchTouchEvent,result=" + result);
        return result;
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        Log.d("eventInfo--->", this.getClass().getSimpleName() + " onTouchEvent,action=" + MotionEvent.actionToString(ev.getAction()));
        boolean result = super.onTouchEvent(ev);
        Log.d("eventInfo--->", this.getClass().getSimpleName() + " onTouchEvent,result=" + result);
        return result;
    }
}

ViewC是一个自定义的Button

@SuppressLint("AppCompatCustomView")
public class ViewC extends Button {
    public ViewC(Context context) {
        super(context);
    }

    public ViewC(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

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

    @TargetApi(Build.VERSION_CODES.KITKAT)
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.d("eventInfo--->", this.getClass().getSimpleName() + " dispatchTouchEvent,action=" + MotionEvent.actionToString(ev.getAction()));
        boolean result = super.dispatchTouchEvent(ev);
        Log.d("eventInfo--->", this.getClass().getSimpleName() + " dispatchTouchEvent,result=" + result);
        return result;
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        Log.d("eventInfo--->", this.getClass().getSimpleName() + " onTouchEvent,action=" + MotionEvent.actionToString(ev.getAction()));
        boolean result = super.onTouchEvent(ev);
        Log.d("eventInfo--->", this.getClass().getSimpleName() + " onTouchEvent,result=" + result);
        return result;
    }
}

在一切都是默认的情况下,让我们点击一下视图当中的ViewC,看看会打印出什么样的Log信息

场景1:只点击ViewA区域,不点击ViewB和ViewC区域

01-31 15:59:42.653 11421-11421/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,action=ACTION_DOWN
01-31 15:59:42.653 11421-11421/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,action=ACTION_DOWN
01-31 15:59:42.653 11421-11421/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,result=false
01-31 15:59:42.653 11421-11421/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onTouchEvent,action=ACTION_DOWN
01-31 15:59:42.654 11421-11421/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onTouchEvent,result=false
01-31 15:59:42.654 11421-11421/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,result=false

事件分析:
从这里可以看到,只点击单个ViewGroup时,引发了两个事件的传递,一个是ACTION_DOWN点击事件的传递,一个是结果的传递。
对于ACTION_DOWN这个事件的传递,方法调用的顺序是:dispatchTouchEvent(MotionEvent ev)–>onInterceptTouchEvent(MotionEvent ev)–>onTouchEvent(MotionEvent ev)(事件分发–>事件拦截—>事件处理)

01-31 16:42:00.078 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,action=ACTION_DOWN
01-31 16:42:00.078 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,action=ACTION_DOWN
01-31 16:42:00.078 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onTouchEvent,action=ACTION_DOWN

对于结果的传递,方法调用的顺序是:onInterceptTouchEvent(MotionEvent ev)–>onTouchEvent(MotionEvent ev)–>dispatchTouchEvent(MotionEvent ev)(事件拦截–>事件处理–>事件分发)

01-31 16:42:00.078 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,result=false
01-31 16:42:00.078 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onTouchEvent,result=false
01-31 16:42:00.078 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,result=false

注意:不知各位有没有看出来,事件处理的触发是在事件拦截之后调用的。

场景2:点击ViewB区域,这次受影响的是ViewA和ViewB

01-31 16:25:24.213 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,action=ACTION_DOWN
01-31 16:25:24.213 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,action=ACTION_DOWN
01-31 16:25:24.213 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,result=false
01-31 16:25:24.213 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,action=ACTION_DOWN
01-31 16:25:24.213 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,action=ACTION_DOWN
01-31 16:25:24.213 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,result=false
01-31 16:25:24.213 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onTouchEvent,action=ACTION_DOWN
01-31 16:25:24.214 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onTouchEvent,result=false
01-31 16:25:24.214 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,result=false
01-31 16:25:24.214 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onTouchEvent,action=ACTION_DOWN
01-31 16:25:24.214 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onTouchEvent,result=false
01-31 16:25:24.214 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,result=false

事件分析:
从这里可以看到,点击单个ViewB时,受影响的是两个ViewGroup(ViewA/ViewB)引发了两个事件的传递,一个是ACTION_DOWN点击事件的传递,一个是结果的传递。
对于ACTION_DOWN这个事件的传递,方法调用的顺序是:ViewGroupA的dispatchTouchEvent(MotionEvent ev)–>ViewGroupA的onInterceptTouchEvent(MotionEvent ev)–>ViewGroupB的dispatchTouchEvent(MotionEvent ev)–>ViewB的onTouchEvent(MotionEvent ev)–>ViewA的onTouchEvent(MotionEvent ev)(ViewA的事件分发–>ViewA的事件拦截—>ViewB的事件分发–>ViewB的事件拦截—>ViewB事件处理–>ViewA的事件处理)

01-31 16:33:33.545 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,action=ACTION_DOWN
01-31 16:33:33.545 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,action=ACTION_DOWN
01-31 16:33:33.546 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,action=ACTION_DOWN
01-31 16:33:33.546 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,action=ACTION_DOWN
01-31 16:33:33.546 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onTouchEvent,action=ACTION_DOWN
01-31 16:33:33.546 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onTouchEvent,action=ACTION_DOWN

对于结果的传递,方法调用的顺序是:ViewA的onInterceptTouchEvent(MotionEvent ev)–>ViewB的onInterceptTouchEvent(MotionEvent ev)–>ViewB的onTouchEvent(MotionEvent ev)–>ViewB的dispatchTouchEvent(MotionEvent ev)–>ViewA的onTouchEvent(MotionEvent ev)–>ViewB的dispatchTouchEvent(MotionEvent ev)(ViewA的事件拦截–>ViewB的事件拦截–>ViewB的事件处理–>ViewB的事件分发–ViewA的事件处理–>ViewA的事件分发)

01-31 16:33:33.546 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,result=false
01-31 16:33:33.546 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,result=false
01-31 16:33:33.546 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onTouchEvent,result=false
01-31 16:33:33.546 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,result=false
01-31 16:33:33.546 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onTouchEvent,result=false
01-31 16:33:33.546 10897-10897/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,result=false

场景3:点击ViewC,这次受影响的是ViewA ViewB和ViewC
从打印的log看,情况就比较复杂了。

01-31 17:09:45.525 17945-17945/com.example.lenovo.testdemo D/ViewRootImpl@db0c345[InterceptActivity]: ViewPostImeInputStage processPointer 0
01-31 17:09:45.525 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,action=ACTION_DOWN
01-31 17:09:45.525 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,action=ACTION_DOWN
01-31 17:09:45.526 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,result=false
01-31 17:09:45.526 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,action=ACTION_DOWN
01-31 17:09:45.526 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,action=ACTION_DOWN
01-31 17:09:45.526 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,result=false
01-31 17:09:45.526 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC dispatchTouchEvent,action=ACTION_DOWN
01-31 17:09:45.526 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC onTouchEvent,action=ACTION_DOWN
01-31 17:09:45.527 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC onTouchEvent,result=true
01-31 17:09:45.527 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC dispatchTouchEvent,result=true
01-31 17:09:45.527 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,result=true
01-31 17:09:45.527 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,result=true
01-31 17:09:45.550 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,action=ACTION_MOVE
01-31 17:09:45.551 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,action=ACTION_MOVE
01-31 17:09:45.551 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,result=false
01-31 17:09:45.551 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,action=ACTION_MOVE
01-31 17:09:45.551 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,action=ACTION_MOVE
01-31 17:09:45.551 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,result=false
01-31 17:09:45.551 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC dispatchTouchEvent,action=ACTION_MOVE
01-31 17:09:45.551 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC onTouchEvent,action=ACTION_MOVE
01-31 17:09:45.551 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC onTouchEvent,result=true
01-31 17:09:45.551 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC dispatchTouchEvent,result=true
01-31 17:09:45.551 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,result=true
01-31 17:09:45.551 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,result=true
01-31 17:09:45.573 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,action=ACTION_MOVE
01-31 17:09:45.573 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,action=ACTION_MOVE
01-31 17:09:45.573 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,result=false
01-31 17:09:45.573 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,action=ACTION_MOVE
01-31 17:09:45.574 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,action=ACTION_MOVE
01-31 17:09:45.574 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,result=false
01-31 17:09:45.574 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC dispatchTouchEvent,action=ACTION_MOVE
01-31 17:09:45.574 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC onTouchEvent,action=ACTION_MOVE
01-31 17:09:45.574 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC onTouchEvent,result=true
01-31 17:09:45.574 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC dispatchTouchEvent,result=true
01-31 17:09:45.574 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,result=true
01-31 17:09:45.574 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,result=true
01-31 17:09:45.590 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,action=ACTION_MOVE
01-31 17:09:45.591 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,action=ACTION_MOVE
01-31 17:09:45.591 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,result=false
01-31 17:09:45.591 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,action=ACTION_MOVE
01-31 17:09:45.591 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,action=ACTION_MOVE
01-31 17:09:45.591 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,result=false
01-31 17:09:45.591 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC dispatchTouchEvent,action=ACTION_MOVE
01-31 17:09:45.591 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC onTouchEvent,action=ACTION_MOVE
01-31 17:09:45.591 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC onTouchEvent,result=true
01-31 17:09:45.591 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC dispatchTouchEvent,result=true
01-31 17:09:45.591 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,result=true
01-31 17:09:45.591 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,result=true
01-31 17:09:45.594 17945-17945/com.example.lenovo.testdemo D/ViewRootImpl@db0c345[InterceptActivity]: ViewPostImeInputStage processPointer 1
01-31 17:09:45.594 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,action=ACTION_UP
01-31 17:09:45.594 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,action=ACTION_UP
01-31 17:09:45.594 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,result=false
01-31 17:09:45.594 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,action=ACTION_UP
01-31 17:09:45.594 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,action=ACTION_UP
01-31 17:09:45.594 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,result=false
01-31 17:09:45.595 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC dispatchTouchEvent,action=ACTION_UP
01-31 17:09:45.595 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC onTouchEvent,action=ACTION_UP
01-31 17:09:45.595 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC onTouchEvent,result=true
01-31 17:09:45.595 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC dispatchTouchEvent,result=true
01-31 17:09:45.595 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,result=true
01-31 17:09:45.595 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,result=true

没关系,我们一点点分析。首先还是看具体的ACTION调用顺序,由于比较长,这里就不再用箭头的形式进行汇总了,看过滤后的结果。

01-31 17:16:52.510 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,action=ACTION_DOWN
01-31 17:16:52.510 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,action=ACTION_DOWN
01-31 17:16:52.510 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,action=ACTION_DOWN
01-31 17:16:52.511 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,action=ACTION_DOWN
01-31 17:16:52.511 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC dispatchTouchEvent,action=ACTION_DOWN
01-31 17:16:52.511 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC onTouchEvent,action=ACTION_DOWN
01-31 17:16:52.534 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,action=ACTION_MOVE
01-31 17:16:52.534 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,action=ACTION_MOVE
01-31 17:16:52.534 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,action=ACTION_MOVE
01-31 17:16:52.534 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,action=ACTION_MOVE
01-31 17:16:52.534 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC dispatchTouchEvent,action=ACTION_MOVE
01-31 17:16:52.534 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC onTouchEvent,action=ACTION_MOVE
01-31 17:16:52.548 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,action=ACTION_MOVE
01-31 17:16:52.548 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,action=ACTION_MOVE
01-31 17:16:52.548 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,action=ACTION_MOVE
01-31 17:16:52.548 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,action=ACTION_MOVE
01-31 17:16:52.549 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC dispatchTouchEvent,action=ACTION_MOVE
01-31 17:16:52.549 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC onTouchEvent,action=ACTION_MOVE
01-31 17:16:52.549 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,action=ACTION_UP
01-31 17:16:52.549 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,action=ACTION_UP
01-31 17:16:52.549 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,action=ACTION_UP
01-31 17:16:52.549 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,action=ACTION_UP
01-31 17:16:52.549 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC dispatchTouchEvent,action=ACTION_UP
01-31 17:16:52.549 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC onTouchEvent,action=ACTION_UP

由上面的结果可以看出,不管是ACTION_DOWN ACTION_MOVE还是ACTION_UP发生时,都是重复这同样的一个套路:由外而内,由父而子,依次调用着ViewA的(事件分发–>事件拦截)—>ViewB的(事件分发–>事件拦截)–ViewC的(事件分发–>事件处理)–END

我们再看result的传递方向

01-31 17:19:41.340 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,result=false
01-31 17:19:41.340 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,result=false
01-31 17:19:41.341 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC onTouchEvent,result=true
01-31 17:19:41.341 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC dispatchTouchEvent,result=true
01-31 17:19:41.341 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,result=true
01-31 17:19:41.341 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,result=true
01-31 17:19:41.363 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,result=false
01-31 17:19:41.363 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,result=false
01-31 17:19:41.364 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC onTouchEvent,result=true
01-31 17:19:41.364 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC dispatchTouchEvent,result=true
01-31 17:19:41.364 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,result=true
01-31 17:19:41.364 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,result=true
01-31 17:19:41.381 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,result=false
01-31 17:19:41.381 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,result=false
01-31 17:19:41.381 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC onTouchEvent,result=true
01-31 17:19:41.381 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC dispatchTouchEvent,result=true
01-31 17:19:41.381 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,result=true
01-31 17:19:41.381 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,result=true
01-31 17:19:41.397 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,result=false
01-31 17:19:41.397 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,result=false
01-31 17:19:41.397 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC onTouchEvent,result=true
01-31 17:19:41.397 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC dispatchTouchEvent,result=true
01-31 17:19:41.397 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,result=true
01-31 17:19:41.397 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,result=true
01-31 17:19:41.414 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,result=false
01-31 17:19:41.414 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,result=false
01-31 17:19:41.414 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC onTouchEvent,result=true
01-31 17:19:41.414 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC dispatchTouchEvent,result=true
01-31 17:19:41.414 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,result=true
01-31 17:19:41.414 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,result=true
01-31 17:19:41.418 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,result=false
01-31 17:19:41.418 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,result=false
01-31 17:19:41.418 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC onTouchEvent,result=true
01-31 17:19:41.418 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC dispatchTouchEvent,result=true
01-31 17:19:41.418 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,result=true
01-31 17:19:41.418 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,result=true

不难看出,上面的日志一直重复这类似于下面的动作。

01-31 17:19:41.340 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,result=false
01-31 17:19:41.340 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,result=false
01-31 17:19:41.341 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC onTouchEvent,result=true
01-31 17:19:41.341 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewC dispatchTouchEvent,result=true
01-31 17:19:41.341 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,result=true
01-31 17:19:41.341 17945-17945/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,result=true

由上面的结果可以看出,不管是resut的传递机制是由外而内、由父儿子依次调用外层的事件拦截,知道遇到事件处理,然后再由内而外、由子而父调用事件分发。

场景4:点击ViewC,但是将ViewB的onInterceptTouchEvent(MotionEvent ev)方法返回true

02-01 09:01:52.345 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,action=ACTION_DOWN
02-01 09:01:52.345 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,action=ACTION_DOWN
02-01 09:01:52.345 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,result=false
02-01 09:01:52.345 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,action=ACTION_DOWN
02-01 09:01:52.345 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,action=ACTION_DOWN
02-01 09:01:52.345 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,result=true
02-01 09:01:52.345 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onTouchEvent,action=ACTION_DOWN
02-01 09:01:52.345 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onTouchEvent,result=false
02-01 09:01:52.345 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,result=false
02-01 09:01:52.345 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onTouchEvent,action=ACTION_DOWN
02-01 09:01:52.345 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onTouchEvent,result=false
02-01 09:01:52.345 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,result=false

我们先过滤一下ACTION操作

02-01 09:01:52.345 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,action=ACTION_DOWN
02-01 09:01:52.345 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,action=ACTION_DOWN
02-01 09:01:52.345 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,action=ACTION_DOWN
02-01 09:01:52.345 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,action=ACTION_DOWN
02-01 09:01:52.345 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onTouchEvent,action=ACTION_DOWN
02-01 09:01:52.345 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onTouchEvent,action=ACTION_DOWN

可以很清楚地看到,整个过程ViewC没有参与,原因显然:ViewB将这个触摸事件进行了拦截,ViewC没有得到参与的机会。所以,进行了ViewA的(事件分发–>事件拦截)–>ViewB的(事件分发–>事件拦截)–>事件B的事件处理–>ViewA的事件处理。
再过滤下事件是处理结果

02-01 09:10:55.100 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,result=false
02-01 09:10:55.100 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onInterceptTouchEvent,result=true
02-01 09:10:55.100 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB onTouchEvent,result=false
02-01 09:10:55.100 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,result=false
02-01 09:10:55.100 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onTouchEvent,result=false
02-01 09:10:55.100 20510-20510/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,result=false

可以看到,默认情况下ViewGroup类型的视图在事件处理上返回的结果都是false,不消费这个点击事件。
如何消费这个事件呢,我们可以在onTouchEvent这个方法中返回true即可。

场景5:测试拦截事件

public class InterceptActivity extends Activity{

    ViewGroupA viewGroupA;
    ViewGroupB viewGroupB;
    ViewC viewC;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_intercept);
        viewGroupA = (ViewGroupA)findViewById(R.id.viewGroupA);
        viewGroupB = (ViewGroupB)findViewById(R.id.viewGroupB);
        viewC = (ViewC)findViewById(R.id.viewC);
        viewGroupA.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if(MotionEvent.ACTION_DOWN==motionEvent.getAction()){
                    Log.d("eventInfo-->","ViewGroupA is on click");
                }
                return false;
            }
        });
        viewGroupB.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if(MotionEvent.ACTION_DOWN==motionEvent.getAction()){
                    Log.d("eventInfo-->","ViewGroupB is on click");
                }
                return false;
            }
        });
        viewC.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if(MotionEvent.ACTION_DOWN==motionEvent.getAction()){
                    Log.d("eventInfo-->","ViewC is on click");
                }
                return false;
            }
        });
    }
}

我们在Activity中设置三个View,并设置三个View的onTouchEvent事件。
5-1)默认情况下(ViewA ViewB都不拦截),点击ViewC
点击的结果是

02-01 09:37:42.393 8192-8192/com.example.lenovo.testdemo D/eventInfo-->: ViewC is on click

只有最内层的View(ViewC)触发了点击事件。
5-2)ViewA的dispatchTouchEvent(MotionEvent ev)返回false,即ViewA不分发,点击ViewC

02-01 09:42:59.795 19781-19781/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,action=ACTION_DOWN
02-01 09:42:59.795 19781-19781/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,result=false

ViewA不分发,导致内部的所有控件全程无法参与整个事件,故ViewB ViewC没有任何事件发生。另外,不分发的直接后果还有就是其本身的事件拦截和事件处理方法无法触发,不能调用到。所以,ViewA的事件分发方法得到了调用。
5-3)ViewA的onInterceptTouchEvent(MotionEvent ev)返回true,即ViewA进行事件拦截,点击ViewC

02-01 09:50:19.114 6061-6061/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,action=ACTION_DOWN
02-01 09:50:19.114 6061-6061/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,action=ACTION_DOWN
02-01 09:50:19.114 6061-6061/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,result=true
02-01 09:50:19.115 6061-6061/com.example.lenovo.testdemo D/eventInfo-->: ViewGroupA is on click
02-01 09:50:19.115 6061-6061/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onTouchEvent,action=ACTION_DOWN
02-01 09:50:19.115 6061-6061/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onTouchEvent,result=false
02-01 09:50:19.115 6061-6061/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,result=false

拦截之后,其内部的View得不到整个事件的参与权,故ViewB ViewC没有任何事件得到调用。我们看到,打印出了“ViewGroupA is on click”。这就说明,ViewA消费掉了整个点击事件。所以,可以说当一个ViewGroup内部的ViewGroup消费不到或者拒绝消费某个事件的时候,这个事件最终要它来消费掉。
5-3)ViewB的dispatchTouchEvent(MotionEvent ev)返回false,即ViewB不进行事件分发,点击ViewC
根据上面的推理,这种局面的结果应该是:ViewA所有事件都得到调用,ViewB只调用事件分发方法,ViewC全程无参与。最终整个点击事件也会让ViewA消费掉。
我们看一下最终的日志

02-01 10:00:15.668 30331-30331/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,action=ACTION_DOWN
02-01 10:00:15.668 30331-30331/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,action=ACTION_DOWN
02-01 10:00:15.668 30331-30331/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onInterceptTouchEvent,result=false
02-01 10:00:15.668 30331-30331/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,action=ACTION_DOWN
02-01 10:00:15.668 30331-30331/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupB dispatchTouchEvent,result=false
02-01 10:00:15.668 30331-30331/com.example.lenovo.testdemo D/eventInfo-->: ViewGroupA is on click
02-01 10:00:15.668 30331-30331/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onTouchEvent,action=ACTION_DOWN
02-01 10:00:15.668 30331-30331/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA onTouchEvent,result=false
02-01 10:00:15.669 30331-30331/com.example.lenovo.testdemo D/eventInfo--->: ViewGroupA dispatchTouchEvent,result=false

日志信息显示的结果跟推理的结果一致。
5-3)ViewB的onInterceptTouchEvent(MotionEvent ev)返回true,即ViewB进行事件拦截,点击ViewC
推理:ViewA的全部事件得到调用,ViewB全部事件得到调用,由于ViewB的拦截ViewC得不到整个事件的参与权。从结果上来看,ViewB拦截了这个事件,本着谁拦截谁处理的原则,ViewB会处理这个结果。但是,由于它默认是是返回的false,不消费这个ACTION_DOWN事件。那么只能往上传递到父控件ViewA,又因为ViewA根本没法推卸责任,只能自尝苦果,将点击事件消费掉。

02-01 10:22:43.834 17229-17229/com.example.lenovo.testdemo D/eventInfo-->: ViewGroupB is on click
02-01 10:22:43.834 17229-17229/com.example.lenovo.testdemo D/eventInfo-->: ViewGroupA is on click

5-4)ViewC的dispatchTouchEvent(MotionEvent ev) 返回false,点击ViewC
推理:ViewB ViewA获取事件,但不消耗

02-01 10:26:43.752 27914-27914/com.example.lenovo.testdemo D/eventInfo-->: ViewGroupB is on click
02-01 10:26:43.752 27914-27914/com.example.lenovo.testdemo D/eventInfo-->: ViewGroupA is on click

5-5)ViewC的onTouchEvent(MotionEvent ev) 返回false,点击ViewC
推理:ViewC ViewB ViewA获取事件,但不消耗.

02-01 10:29:30.426 1911-1911/com.example.lenovo.testdemo D/eventInfo-->: ViewC is on click
02-01 10:29:30.426 1911-1911/com.example.lenovo.testdemo D/eventInfo-->: ViewGroupB is on click
02-01 10:29:30.426 1911-1911/com.example.lenovo.testdemo D/eventInfo-->: ViewGroupA is on click

5-6)ViewC的onTouchEvent(MotionEvent ev) 返回true,点击ViewC
推理:ViewC消耗了这个事件。事件消耗就终止了,不会再往上传送,故只有ViewA出触发。

02-01 10:31:11.736 7330-7330/com.example.lenovo.testdemo D/eventInfo-->: ViewC is on click

事件分发机制总结

通过上面的代码探究和日志结果,对Android中View的事件分发和事件拦截机制总结如下。

1)同一件事件序列是从手指接触屏幕的那一刻开始,到手指离开屏幕。会经历ACTION_DOWN–>ACTION_UP,如果有手指的滑动时会有ACTION_DOWN–>ACTION_MOVE…..ACTION_MOVE–>ACTION_UP.
2)ViewGroup含有事件分发、事件拦截和事件处理3个重要的方法,View只有事件分发和事件处理2个方法,不能够对事件进行拦截。
3) 默认情况下,ViewGroup的事件分发方法返回true,即可以正常地将事件分发下去;事件拦截方法返回的是false,即不对进过自身的事件进行拦截;事件处理方法返回的是false,即不消耗当前事件。
4)默认情况下,View的事件分发方法返回true,即可以正常地将事件分发下去;事件处理方法返回true,即主动将事件消耗掉。
5)事件分发方法dispatchTouchEvent(MotionEvent ev)的作用域是当前ViewGroup的事件拦截方法、事件处理方法和当前ViewGroup中所有的字类ViewGroup/View。就是说,如果当前的ViewGroup不分发改事件的话,当前ViewGroup中的事件拦截、事件处理和当前ViewGroup中所有的字类ViewGroup/View统统得不到任何事件参与权。
6)事件拦截方法的作用域是当前ViewGroup中所有的字类ViewGroup/View。即如果启动了事件拦截,当前ViewGroup中所有的字类ViewGroup/View得不到任何事件参与权。并且,“谁拦截谁处理”,当前ViewGroup会启动事件处理。
7)事件的最终消耗与否有一个硬性指标—-onTouchEvent(MotionEvent ev) 的事件返回值。如果是返回的true,那么事件到目前为止,不再向上层传递。一直找到返回true的地方为止,如果一直找不到的话,事件最终将会被activity消耗掉。默认情况下,事件将会被最内层的view消耗掉。
8)View的enable属性不会影响onTouchEvent的默认返回值。该返回true,还是会返回true。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值