事件分发机制是Android中十三分重大的3个知识点,事件分发机制是Android中充足关键的贰个知识点

事件分发机制是Android中十分紧要的1个知识点,同时也是难关,相信到近期甘休很多Android开发者对事件分发机制并没有2个要命系统的认识,当然也包蕴博主个人在内。只怕在平时的费用工作中大家并没有发现到事件分发机制起到的成效,其实它是天天存在的只是我们不了然则已,似乎有个别滑行争论、点击事件时期的争持等等大多是因为事件分发处理不当导致的。想起了博主大学时做过一个小项目,里面就涌出了滑动冲突的标题,就算最终在网上一步步瞅着人家的教程也糊里糊涂的消除了,但毕竟不知其所以然,那么明日就让我们一齐来深刻的探索一下事变分发机制吗。

事件分发机制是Android中万分紧要的一个知识点,同时也是难关,相信到近日甘休很多Android开发者对事件分发机制并不曾2个老大系统的认识,当然也包蕴博主个人在内。只怕在平日的开发工作中大家并不曾发现到事件分发机制起到的机能,其实它是时刻存在的只是我们不知道而已,似乎有的滑动龃龉、点击事件时期的争论等等大多是因为事件分发处理不当导致的。想起了博主大学时做过七个小品种,里面就应运而生了滑动争持的题材,固然最后在网上一步步看着外人的教程也糊里糊涂的解决了,但终归不知其所以然,那么后天就让大家一同来长远的探赜索隐一下事变分发机制吗。

哪些是事件分发机制?

说了半天的风波分发机制那终究是个吗东西吗?我们毫不把它想象的那么高深莫测,不要在思维上给协调设上阻碍,其实很不难通晓,博主的知晓是:简单的话,事件分发机制就是Android系统对事件传递进程规定的一种事件传递规则,事件都会遵从这一个规则进行分发传递。

在探究事件分发机制在此以前,大家先来规定一下解析的步调,化整为零,各种击破:

  • 弄通晓分析目的:Motion伊芙nt。
  • 精通多个章程:dispatchTouch伊芙nt(Motion伊芙nt
    event)、onInterceptTouch伊芙nt(Motion
    event)、onTouch伊夫nt(Motion伊夫nt event)。
  • Motion伊夫nt事件的传递进度
  • 小结

什么是事件分发机制?

说了半天的事件分发机制这到底是个啥东西呢?大家不用把它想象的那么高深莫测,不要在思想上给自身设上阻碍,其实很简单了然,博主的精晓是:一句话来说,事件分发机制就是Android系统对事件传递进程规定的一种事件传递规则,事件都会依照这几个规则进行分发传递。

在研讨事件分发机制之前,我们先来显然一下剖析的步子,化整为零,各样击破:

  • 弄精通分析目标:MotionEvent。
  • 叩问三个艺术:dispatchTouch伊芙nt(Motion伊芙nt
    event)、onInterceptTouch伊芙nt(Motion
    event)、onTouch伊夫nt(Motion伊夫nt event)。
  • Motion伊夫nt事件的传递进度
  • 小结

MotionEvent

实则点击事件的散发进程就是对Motion伊夫nt事件的分发进度,当用户点击操作按下后,Motion伊夫nt事件随后爆发并经过一定的条条框框传递到钦赐的View上,那些传递的历程和规则就是事件分发机制。

而点击操作触发Motion伊芙nt事件是3个轩然大波流可能说是三个事件种类,其非凡的事件类型有如下二种:

  • MotionEvent.ACTION_DOWN:手指刚点下屏幕时接触此类型。
  • MotionEvent.ACTION_MOVE:手指在显示器上活动时会数十一回接触此类型。
  • MotionEvent.ACTION_UP:手指在屏幕上抬起时接触此类型。

要特别注意的是,平时状态下三个Motion伊夫nt事件系列包蕴一个 ACTION_DOWN
若干个 ACTION_MOVE 和 ACTION_UP
是二个一体化的事件种类。(点下来立马抬起指头时,会唯有 ACTION_DOWN 和
ACTION_UP,那也是1个全体的风云系列)

MotionEvent

实在点击事件的分发进程就是对Motion伊夫nt事件的散发进度,当用户点击操作按下后,Motion伊夫nt事件随后暴发并经过一定的条条框框传递到钦赐的View上,那一个传递的进度和规则就是事件分发机制。

而点击操作触发Motion伊夫nt事件是多个轩然大波流或然说是2个事件种类,其独立的事件类型有如下二种:

  • MotionEvent.ACTION_DOWN:手指刚点下屏幕时接触此类型。
  • MotionEvent.ACTION_MOVE:手指在显示屏上活动时会数十四次触及此类型。
  • MotionEvent.ACTION_UP:手指在显示屏上抬起时接触此类型。

要尤其注意的是,平常景况下3个Motion伊芙nt事件系列包括1个 ACTION_DOWN
若干个 ACTION_MOVE 和 ACTION_UP
是2个完全的轩然大波体系。(点下来立马抬起指头时,会唯有 ACTION_DOWN 和
ACTION_UP,那也是3个完好无损的风波系列)

dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent

  • boolean dispatchTouchEvent (MotionEvent event):

分发事件,只要事件能传递到近期View就必定会调用此办法,其重返值是2个布尔类型表示是或不是消耗事件。重回true代表消耗事件,事件流的接续部分还会跟着传递过来;再次来到false代表不消耗事件,事件流的持续部分就不再传递于此。

  • boolean onInterceptTouchEvent (MotionEvent ev):

此格局表示是或不是拦截Motion伊芙nt事件,唯有ViewGroup类型的控件才有此方法。即使此办法重返true表示拦截事件,事件将传递给当下View的onTouch伊夫nt()方法,而不再向其麾下的View传递。假设此方法重临false表示不阻拦事件,事件将传递给下属View的dispatchTouch伊芙nt()。

  • boolean onTouchEvent (MotionEvent event):

此方式用来拍卖Motion伊芙nt,重临值表示是不是消耗事件。重返true表示消耗事件,那么事件流的接轨部分还会传送过来;重返false表示不消耗事件,事件将提交上级View的onTouch伊芙nt()处理,假若上边View的onTouch伊夫nt()仍旧重临false,那么事件将再付诸上级的顶头上司处理,以此类推,假诺各级View的onTouch伊夫nt()都不消耗事件,那么事件最后将交由Activity的onTouch伊芙nt()处理。

上文说了那般多照旧不够具体,先用流程图大体说爱他美(Aptamil)(Beingmate)个之上五个主意的关系,及调用流程,下文还会结合实际示例详细表明在事件分发传递中相继艺术的调用规则。

三者关系大体如下图:

图片 1

dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent

  • boolean dispatchTouchEvent (MotionEvent event):

分发事件,只要事件能传递到日前View就自然会调用此措施,其重临值是贰个布尔类型表示是还是不是消耗事件。重回true代表消耗事件,事件流的延续部分还会随之传递过来;重回false代表不消耗事件,事件流的继承部分就不再传递于此。

  • boolean onInterceptTouchEvent (MotionEvent ev):

此办法表示是或不是拦截Motion伊夫nt事件,唯有ViewGroup类型的控件才有此方法。若是此情势再次来到true表示拦截事件,事件将传递给当下View的onTouch伊芙nt()方法,而不再向其麾下的View传递。若是此措施重临false表示不阻拦事件,事件将传递给下属View的dispatchTouch伊芙nt()。

  • boolean onTouchEvent (MotionEvent event):

此措施用来处理Motion伊芙nt,再次来到值表示是或不是消耗事件。再次回到true表示消耗事件,那么事件流的存续部分还会传送过来;重返false表示不消耗事件,事件将交给上级View的onTouch伊夫nt()处理,倘使上级View的onTouch伊夫nt()照旧再次来到false,那么事件将再付诸上级的上边处理,以此类推,即使各级View的onTouch伊夫nt()都不消耗事件,那么事件结尾将提交Activity的onTouch伊芙nt()处理。

上文说了如此多依然不够具体,先用流程图大体说美赞臣个之上七个章程的涉及,及调用流程,下文还会结合实际示例详细表达在事件分发传递中逐条艺术的调用规则。

三者关系大体如下图:

图片 2

Motion伊芙nt事件传递进度

当手率领击显示器发出三个Touch事件后,事件根据Activity->Window->View的依次依次传递。

首先会传送给Activity的dispatchTouch伊芙nt(),在此办法内部会将由Window处理,接着事件会传送给根View,根View接收到事件后就会依照事件分发机制去处总管件。

根View在此地就是二个ViewGroup,它在经受到事件后会调用dispatchTouch伊夫nt(),在此方法内部会通过onInterceptTouch伊芙nt()方法判断是不是拦截事件,若是onInterceptTouchEvent()重临true就代表它要阻拦事件,事件将传递给当下ViewGroup的onTouch伊夫nt()。假诺onInterceptTouch伊夫nt()放回false就象征它不阻碍事件,事件将传给其下属的View,调用下级View的dispatchTouch伊夫nt()。

根View的上面View恐怕又是三个ViewGroup,若是那样的话其传递流程同根View一样。无论根View的手下人View是或不是ViewGroup,如若不阻拦事件,最后事件会传送到多少个纯View的控件上。

当三个View(纯View控件)接收到事件后,也会调用其dispatchTouch伊芙nt(),然后在此方法内部会调用当前View的onTouch伊芙nt(),固然onTouch伊夫nt()再次回到true则意味要拍卖此事件。假设回到false表示不消耗事件,其上级View的onTouch伊芙nt()将被调用,则事件流的存续部分不再传递到日前View,在贰个风浪流中也不会再调用当前View的dispatchTouch伊芙nt()。

接下去通过具体示例来查看事件传递的流水线:

Motion伊芙nt事件传递进度

当手率领击显示屏暴发三个Touch事件后,事件依照Activity->Window->View的顺序依次传递。

第2会传递给Activity的dispatchTouch伊夫nt(),在此情势内部会将由Window处理,接着事件会传递给根View,根View接收到事件后就会依照事件分发机制去处管事人件。

根View在此处就是五个ViewGroup,它在接受到事件后会调用dispatchTouch伊夫nt(),在此办法内部会经过onInterceptTouch伊夫nt()方法判断是或不是拦截事件,即使onInterceptTouch伊夫nt()重返true就意味着它要堵住事件,事件将传递给当下ViewGroup的onTouch伊夫nt()。假设onInterceptTouch伊夫nt()放回false就象征它不阻碍事件,事件将传给其下属的View,调用下级View的dispatchTouch伊夫nt()。

根View的下边View或者又是3个ViewGroup,假若那样的话其传递流程同根View一样。无论根View的手下人View是或不是ViewGroup,如若不阻碍事件,最终事件会传递到二个纯View的控件上。

当1个View(纯View控件)接收到事件后,也会调用其dispatchTouch伊夫nt(),然后在此措施内部会调用当前View的onTouch伊夫nt(),假若onTouch伊夫nt()重返true则代表要处理此事件。如若回到false表示不消耗事件,其上边View的onTouch伊芙nt()将被调用,则事件流的接续部分不再传递到近日View,在3个事变流中也不会再调用当前View的dispatchTouch伊夫nt()。

接下去通过实际示例来查阅事件传递的流水线:

示例一,暗许情状下的风浪传递流程

开创一个类,2个Activity、三个继承自LinearLayout的View,壹个持续自Button的View,因人而异写他们的dispatchTouch伊芙nt()、onIntercepteTouch伊夫nt()、onTouch伊芙nt(),多少个类及布局文件的代码如下:

  • EventDispatchActivity

/**
 * 事件分发机制测试Activity
 * Created by liuwei on 18/1/5.
 */
public class EventDispatchActivity extends AppCompatActivity {

    private final static String TAG = "Activity";//EventDispatchActivity.class.getSimpleName();

    private EventDispatchTestView edtv_test;
    private EventDispatchLinearLayout edll_test;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_event_dispatch);
        edtv_test = ViewUtils.find(this, R.id.edtv_test);
        edll_test = ViewUtils.find(this, R.id.edll_test);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {

        // 被调用时输出log,event.getAction表示事件的类型,0:ACTION_DOWN,1:ACTION_UP,2:ACTION_MOVE。

        Log.i(TAG, "dispatchTouchEvent: " + event.getAction() + " | 分发事件");
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i(TAG, "onTouchEvent: " + event.getAction() + " | 是否消耗事件:" + true);
        return super.onTouchEvent(event);
    }
}
  • EventDispatchLinearLayout

/**
 * 事件分发机制测试 ViewGroup
 * Created by liuwei on 18/1/5.
 */
public class EventDispatchLinearLayout extends LinearLayout {

    private final static String TAG = "——Layout";//EventDispatchLinearLayout.class.getSimpleName();


    public EventDispatchLinearLayout(Context context) {
        super(context);
    }

    public EventDispatchLinearLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.i(TAG, "dispatchTouchEvent: " + event.getAction() + " | 分发事件");
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        Log.i(TAG, "onInterceptTouchEvent: " + event.getAction() + " | 是否拦截:" + false);
        return super.onInterceptTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i(TAG, "onTouchEvent: " + event.getAction() + " | 是否消耗事件:" + false);
        return super.onTouchEvent(event);
    }
}
  • EventDispatchTestView

/**
 * 事件分发机制测试 View
 * Created by liuwei on 18/1/5.
 */
public class EventDispatchTestView extends Button {

    private final static String TAG = "————View";//EventDistpatchTestView.class.getSimpleName();

    public EventDispatchTestView(Context context) {
        super(context);
    }

    public EventDispatchTestView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.i(TAG, "dispatchTouchEvent: " + event.getAction() + " | 分发事件");
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i(TAG, "onTouchEvent: " + event.getAction() + " | 是否消耗事件:" + true);
        return super.onTouchEvent(event);
    }
}
  • 布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical"
    tools:context="cn.codingblock.view.event_dispatch.EventDispatchActivity">

    <cn.codingblock.view.event_dispatch.EventDispatchLinearLayout
        android:id="@+id/edll_test"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#cccccc">

        <cn.codingblock.view.event_dispatch.EventDispatchTestView
            android:id="@+id/edtv_test"
            android:layout_width="300dp"
            android:layout_height="300dp"
            android:layout_margin="10dp"
            android:background="#000000"/>

    </cn.codingblock.view.event_dispatch.EventDispatchLinearLayout>

</LinearLayout>

运营代码,点击伊夫ntDispatchTestView(金黄区域),log输出如下(log中的数字代表事件的系列,0:ACTION_DOWN,1:ACTION_UP,2:ACTION_MOVE):

01-05 16:58:05.574 23295-23295/cn.codingblock.view I/Activity: dispatchTouchEvent: 0 | 分发事件
01-05 16:58:05.574 23295-23295/cn.codingblock.view I/——Layout: dispatchTouchEvent: 0 | 分发事件
01-05 16:58:05.574 23295-23295/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 0 | 是否拦截:false
01-05 16:58:05.574 23295-23295/cn.codingblock.view I/————View: dispatchTouchEvent: 0 | 分发事件
01-05 16:58:05.574 23295-23295/cn.codingblock.view I/————View: onTouchEvent: 0 | 是否消耗事件:true

01-05 16:58:05.611 23295-23295/cn.codingblock.view I/Activity: dispatchTouchEvent: 2 | 分发事件
01-05 16:58:05.611 23295-23295/cn.codingblock.view I/——Layout: dispatchTouchEvent: 2 | 分发事件
01-05 16:58:05.611 23295-23295/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 2 | 是否拦截:false
01-05 16:58:05.611 23295-23295/cn.codingblock.view I/————View: dispatchTouchEvent: 2 | 分发事件
01-05 16:58:05.611 23295-23295/cn.codingblock.view I/————View: onTouchEvent: 2 | 是否消耗事件:true

01-05 16:58:05.619 23295-23295/cn.codingblock.view I/Activity: dispatchTouchEvent: 1 | 分发事件
01-05 16:58:05.619 23295-23295/cn.codingblock.view I/——Layout: dispatchTouchEvent: 1 | 分发事件
01-05 16:58:05.619 23295-23295/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 1 | 是否拦截:false
01-05 16:58:05.620 23295-23295/cn.codingblock.view I/————View: dispatchTouchEvent: 1 | 分发事件
01-05 16:58:05.620 23295-23295/cn.codingblock.view I/————View: onTouchEvent: 1 | 是否消耗事件:true

由log可以看出ViewGroup的onInterceptTouch伊芙nt方法暗中认同是不阻碍事件的,View的onTouch伊芙nt方法暗中同意消耗事件。事件流的ACTION_DOWN类型Motion
伊夫nt率先到达View的onTouch伊夫nt方法中,此时onTouch伊芙nt方法再次回到true,表示要处总管件,所以事件流的三番五次部分如故通过log中的流程到达了View的onTouch伊夫nt方法中。

示例一,暗中认同情形下的风云传递流程

创办二个类,三个Activity、多个接续自LinearLayout的View,三个连任自Button的View,仁同一视写他们的dispatchTouch伊夫nt()、onIntercepteTouch伊夫nt()、onTouch伊芙nt(),多个类及布局文件的代码如下:

  • EventDispatchActivity

/**
 * 事件分发机制测试Activity
 * Created by liuwei on 18/1/5.
 */
public class EventDispatchActivity extends AppCompatActivity {

    private final static String TAG = "Activity";//EventDispatchActivity.class.getSimpleName();

    private EventDispatchTestView edtv_test;
    private EventDispatchLinearLayout edll_test;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_event_dispatch);
        edtv_test = ViewUtils.find(this, R.id.edtv_test);
        edll_test = ViewUtils.find(this, R.id.edll_test);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {

        // 被调用时输出log,event.getAction表示事件的类型,0:ACTION_DOWN,1:ACTION_UP,2:ACTION_MOVE。

        Log.i(TAG, "dispatchTouchEvent: " + event.getAction() + " | 分发事件");
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i(TAG, "onTouchEvent: " + event.getAction() + " | 是否消耗事件:" + true);
        return super.onTouchEvent(event);
    }
}
  • EventDispatchLinearLayout

/**
 * 事件分发机制测试 ViewGroup
 * Created by liuwei on 18/1/5.
 */
public class EventDispatchLinearLayout extends LinearLayout {

    private final static String TAG = "——Layout";//EventDispatchLinearLayout.class.getSimpleName();


    public EventDispatchLinearLayout(Context context) {
        super(context);
    }

    public EventDispatchLinearLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.i(TAG, "dispatchTouchEvent: " + event.getAction() + " | 分发事件");
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        Log.i(TAG, "onInterceptTouchEvent: " + event.getAction() + " | 是否拦截:" + false);
        return super.onInterceptTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i(TAG, "onTouchEvent: " + event.getAction() + " | 是否消耗事件:" + false);
        return super.onTouchEvent(event);
    }
}
  • EventDispatchTestView

/**
 * 事件分发机制测试 View
 * Created by liuwei on 18/1/5.
 */
public class EventDispatchTestView extends Button {

    private final static String TAG = "————View";//EventDistpatchTestView.class.getSimpleName();

    public EventDispatchTestView(Context context) {
        super(context);
    }

    public EventDispatchTestView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.i(TAG, "dispatchTouchEvent: " + event.getAction() + " | 分发事件");
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i(TAG, "onTouchEvent: " + event.getAction() + " | 是否消耗事件:" + true);
        return super.onTouchEvent(event);
    }
}
  • 布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical"
    tools:context="cn.codingblock.view.event_dispatch.EventDispatchActivity">

    <cn.codingblock.view.event_dispatch.EventDispatchLinearLayout
        android:id="@+id/edll_test"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#cccccc">

        <cn.codingblock.view.event_dispatch.EventDispatchTestView
            android:id="@+id/edtv_test"
            android:layout_width="300dp"
            android:layout_height="300dp"
            android:layout_margin="10dp"
            android:background="#000000"/>

    </cn.codingblock.view.event_dispatch.EventDispatchLinearLayout>

</LinearLayout>

运维代码,点击伊芙ntDispatchTestView(浅蓝区域),log输出如下(log中的数字代表事件的类型,0:ACTION_DOWN,1:ACTION_UP,2:ACTION_MOVE):

01-05 16:58:05.574 23295-23295/cn.codingblock.view I/Activity: dispatchTouchEvent: 0 | 分发事件
01-05 16:58:05.574 23295-23295/cn.codingblock.view I/——Layout: dispatchTouchEvent: 0 | 分发事件
01-05 16:58:05.574 23295-23295/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 0 | 是否拦截:false
01-05 16:58:05.574 23295-23295/cn.codingblock.view I/————View: dispatchTouchEvent: 0 | 分发事件
01-05 16:58:05.574 23295-23295/cn.codingblock.view I/————View: onTouchEvent: 0 | 是否消耗事件:true

01-05 16:58:05.611 23295-23295/cn.codingblock.view I/Activity: dispatchTouchEvent: 2 | 分发事件
01-05 16:58:05.611 23295-23295/cn.codingblock.view I/——Layout: dispatchTouchEvent: 2 | 分发事件
01-05 16:58:05.611 23295-23295/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 2 | 是否拦截:false
01-05 16:58:05.611 23295-23295/cn.codingblock.view I/————View: dispatchTouchEvent: 2 | 分发事件
01-05 16:58:05.611 23295-23295/cn.codingblock.view I/————View: onTouchEvent: 2 | 是否消耗事件:true

01-05 16:58:05.619 23295-23295/cn.codingblock.view I/Activity: dispatchTouchEvent: 1 | 分发事件
01-05 16:58:05.619 23295-23295/cn.codingblock.view I/——Layout: dispatchTouchEvent: 1 | 分发事件
01-05 16:58:05.619 23295-23295/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 1 | 是否拦截:false
01-05 16:58:05.620 23295-23295/cn.codingblock.view I/————View: dispatchTouchEvent: 1 | 分发事件
01-05 16:58:05.620 23295-23295/cn.codingblock.view I/————View: onTouchEvent: 1 | 是否消耗事件:true

由log可以看来ViewGroup的onInterceptTouch伊夫nt方法暗中认同是不阻碍事件的,View的onTouch伊芙nt方法暗中同意消耗事件。事件流的ACTION_DOWN类型Motion
伊芙nt率先到达View的onTouch伊夫nt方法中,此时onTouch伊夫nt方法重回true,表示要处监护人件,所以事件流的后续部分依然通过log中的流程到达了View的onTouch伊芙nt方法中。

示例贰 、在示例一的根底上,让View的onTouch伊夫nt不消耗事件时的传递流程

接下去让地方的EventDispatchTestView的onTouch伊夫nt重回false:

@Override
public boolean onTouchEvent(MotionEvent event) {
    Log.i(TAG, "onTouchEvent: " + event.getAction() + " | 是否消耗事件:" + false);
    return false;//super.onTouchEvent(event);
}

测试log如下:

01-05 18:18:52.545 10771-10771/cn.codingblock.view I/Activity: dispatchTouchEvent: 0 | 分发事件
01-05 18:18:52.545 10771-10771/cn.codingblock.view I/——Layout: dispatchTouchEvent: 0 | 分发事件
01-05 18:18:52.546 10771-10771/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 0 | 是否拦截:false
01-05 18:18:52.546 10771-10771/cn.codingblock.view I/————View: dispatchTouchEvent: 0 | 分发事件
01-05 18:18:52.546 10771-10771/cn.codingblock.view I/————View: onTouchEvent: 0 | 是否消耗事件:false
01-05 18:18:52.546 10771-10771/cn.codingblock.view I/——Layout: onTouchEvent: 0 | 是否消耗事件:false
01-05 18:18:52.547 10771-10771/cn.codingblock.view I/Activity: onTouchEvent: 0 | 是否消耗事件:true

01-05 18:18:52.629 10771-10771/cn.codingblock.view I/Activity: dispatchTouchEvent: 2 | 分发事件
01-05 18:18:52.629 10771-10771/cn.codingblock.view I/Activity: onTouchEvent: 2 | 是否消耗事件:true

01-05 18:18:52.630 10771-10771/cn.codingblock.view I/Activity: dispatchTouchEvent: 1 | 分发事件
01-05 18:18:52.630 10771-10771/cn.codingblock.view I/Activity: onTouchEvent: 1 | 是否消耗事件:true

当View的onTouch伊夫nt不消耗事件时,事件会交到ViewGroup的onTouch伊夫nt方法处理,而从log可以看看ViewGroup的onTouch伊芙nt暗许也不消耗事件,所以事件由提交Activity的onTouch伊芙nt方法处理,最终事件流的持续部分不再传递给ViewGroup和View,而是直接传送给Activity的onTouch伊芙nt处理。

示例② 、在示例一的底蕴上,让View的onTouch伊芙nt不消耗事件时的传递流程

接下去让地点的伊芙ntDispatchTestView的onTouch伊芙nt重返false:

@Override
public boolean onTouchEvent(MotionEvent event) {
    Log.i(TAG, "onTouchEvent: " + event.getAction() + " | 是否消耗事件:" + false);
    return false;//super.onTouchEvent(event);
}

测试log如下:

01-05 18:18:52.545 10771-10771/cn.codingblock.view I/Activity: dispatchTouchEvent: 0 | 分发事件
01-05 18:18:52.545 10771-10771/cn.codingblock.view I/——Layout: dispatchTouchEvent: 0 | 分发事件
01-05 18:18:52.546 10771-10771/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 0 | 是否拦截:false
01-05 18:18:52.546 10771-10771/cn.codingblock.view I/————View: dispatchTouchEvent: 0 | 分发事件
01-05 18:18:52.546 10771-10771/cn.codingblock.view I/————View: onTouchEvent: 0 | 是否消耗事件:false
01-05 18:18:52.546 10771-10771/cn.codingblock.view I/——Layout: onTouchEvent: 0 | 是否消耗事件:false
01-05 18:18:52.547 10771-10771/cn.codingblock.view I/Activity: onTouchEvent: 0 | 是否消耗事件:true

01-05 18:18:52.629 10771-10771/cn.codingblock.view I/Activity: dispatchTouchEvent: 2 | 分发事件
01-05 18:18:52.629 10771-10771/cn.codingblock.view I/Activity: onTouchEvent: 2 | 是否消耗事件:true

01-05 18:18:52.630 10771-10771/cn.codingblock.view I/Activity: dispatchTouchEvent: 1 | 分发事件
01-05 18:18:52.630 10771-10771/cn.codingblock.view I/Activity: onTouchEvent: 1 | 是否消耗事件:true

当View的onTouch伊夫nt不消耗事件时,事件会付出ViewGroup的onTouchEvent方法处理,而从log可以看到ViewGroup的onTouch伊芙nt暗中认可也不消耗事件,所以事件由提交Activity的onTouch伊夫nt方法处理,最后事件流的后续部分不再传递给ViewGroup和View,而是径直传送给Activity的onTouchEvent处理。

示例三 、在示例二的基本功上让ViewGroup消耗事件

修改伊夫ntDispatchLinearLayout的onTouch伊夫nt(),让其回来true。

@Override
public boolean onTouchEvent(MotionEvent event) {
    Log.i(TAG, "onTouchEvent: " + event.getAction() + " | 是否消耗事件:" + true);
    return true;//super.onTouchEvent(event);
}

测试log如下:

01-05 18:34:53.409 21169-21169/cn.codingblock.view I/Activity: dispatchTouchEvent: 0 | 分发事件
01-05 18:34:53.409 21169-21169/cn.codingblock.view I/——Layout: dispatchTouchEvent: 0 | 分发事件
01-05 18:34:53.409 21169-21169/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 0 | 是否拦截:false
01-05 18:34:53.409 21169-21169/cn.codingblock.view I/————View: dispatchTouchEvent: 0 | 分发事件
01-05 18:34:53.410 21169-21169/cn.codingblock.view I/————View: onTouchEvent: 0 | 是否消耗事件:false
01-05 18:34:53.410 21169-21169/cn.codingblock.view I/——Layout: onTouchEvent: 0 | 是否消耗事件:true

01-05 18:34:53.420 21169-21169/cn.codingblock.view I/Activity: dispatchTouchEvent: 2 | 分发事件
01-05 18:34:53.420 21169-21169/cn.codingblock.view I/——Layout: dispatchTouchEvent: 2 | 分发事件
01-05 18:34:53.420 21169-21169/cn.codingblock.view I/——Layout: onTouchEvent: 2 | 是否消耗事件:true

01-05 18:34:53.470 21169-21169/cn.codingblock.view I/Activity: dispatchTouchEvent: 1 | 分发事件
01-05 18:34:53.470 21169-21169/cn.codingblock.view I/——Layout: dispatchTouchEvent: 1 | 分发事件
01-05 18:34:53.470 21169-21169/cn.codingblock.view I/——Layout: onTouchEvent: 1 | 是否消耗事件:true

此种景况下,事件流的ACTION_DOWN先到达View的onTouch伊芙nt,发现它不消耗事件,继而重回上级的ViewGroup的onTouch伊夫nt中,发现它要消耗事件,事件流的后续部分就不在传递给View,也不在调用ViewGroup的onInterceptTouch伊夫nt方法,因为早已知晓View不处监护人件,所以没必要再通过onInterceptTouch伊夫nt方法来判定了。

示例叁 、在示例二的功底上让ViewGroup消耗事件

修改伊芙ntDispatchLinearLayout的onTouch伊芙nt(),让其归来true。

@Override
public boolean onTouchEvent(MotionEvent event) {
    Log.i(TAG, "onTouchEvent: " + event.getAction() + " | 是否消耗事件:" + true);
    return true;//super.onTouchEvent(event);
}

测试log如下:

01-05 18:34:53.409 21169-21169/cn.codingblock.view I/Activity: dispatchTouchEvent: 0 | 分发事件
01-05 18:34:53.409 21169-21169/cn.codingblock.view I/——Layout: dispatchTouchEvent: 0 | 分发事件
01-05 18:34:53.409 21169-21169/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 0 | 是否拦截:false
01-05 18:34:53.409 21169-21169/cn.codingblock.view I/————View: dispatchTouchEvent: 0 | 分发事件
01-05 18:34:53.410 21169-21169/cn.codingblock.view I/————View: onTouchEvent: 0 | 是否消耗事件:false
01-05 18:34:53.410 21169-21169/cn.codingblock.view I/——Layout: onTouchEvent: 0 | 是否消耗事件:true

01-05 18:34:53.420 21169-21169/cn.codingblock.view I/Activity: dispatchTouchEvent: 2 | 分发事件
01-05 18:34:53.420 21169-21169/cn.codingblock.view I/——Layout: dispatchTouchEvent: 2 | 分发事件
01-05 18:34:53.420 21169-21169/cn.codingblock.view I/——Layout: onTouchEvent: 2 | 是否消耗事件:true

01-05 18:34:53.470 21169-21169/cn.codingblock.view I/Activity: dispatchTouchEvent: 1 | 分发事件
01-05 18:34:53.470 21169-21169/cn.codingblock.view I/——Layout: dispatchTouchEvent: 1 | 分发事件
01-05 18:34:53.470 21169-21169/cn.codingblock.view I/——Layout: onTouchEvent: 1 | 是否消耗事件:true

此种情形下,事件流的ACTION_DOWN先到达View的onTouch伊芙nt,发现它不消耗事件,继而再次回到上级的ViewGroup的onTouch伊芙nt中,发现它要开支事件,事件流的存续部分就不在传递给View,也不在调用ViewGroup的onInterceptTouch伊芙nt方法,因为早已知道View不处监护人件,所以没必要再通过onInterceptTouch伊夫nt方法来判断了。

示例肆 、假若在ViewGroup的onInterceptTouch伊芙nt中回到了true拦截了事件,整个事件将不再传递给View而是直接交由ViewGroup的onTouch伊芙nt处理。

修改伊夫ntDispatchLinearLayout的onInterceptTouch伊夫nt(),让其回来true。

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    Log.i(TAG, "onInterceptTouchEvent: " + event.getAction() + " | 是否拦截:" + true);
    return true;//super.onInterceptTouchEvent(event);
}

测试log如下:

01-05 19:03:21.788 9733-9733/cn.codingblock.view I/Activity: dispatchTouchEvent: 0 | 分发事件
01-05 19:03:21.789 9733-9733/cn.codingblock.view I/——Layout: dispatchTouchEvent: 0 | 分发事件
01-05 19:03:21.789 9733-9733/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 0 | 是否拦截:true
01-05 19:03:21.789 9733-9733/cn.codingblock.view I/——Layout: onTouchEvent: 0 | 是否消耗事件:true
01-05 19:03:21.819 9733-9733/cn.codingblock.view I/Activity: dispatchTouchEvent: 2 | 分发事件
01-05 19:03:21.819 9733-9733/cn.codingblock.view I/——Layout: dispatchTouchEvent: 2 | 分发事件
01-05 19:03:21.819 9733-9733/cn.codingblock.view I/——Layout: onTouchEvent: 2 | 是否消耗事件:true
01-05 19:03:21.877 9733-9733/cn.codingblock.view I/Activity: dispatchTouchEvent: 1 | 分发事件
01-05 19:03:21.877 9733-9733/cn.codingblock.view I/——Layout: dispatchTouchEvent: 1 | 分发事件
01-05 19:03:21.877 9733-9733/cn.codingblock.view I/——Layout: onTouchEvent: 1 | 是否消耗事件:true

示例④ 、即便在ViewGroup的onInterceptTouchEvent中回到了true拦截了事件,整个事件将不再传递给View而是直接交由ViewGroup的onTouchEvent处理。

修改伊夫ntDispatchLinearLayout的onInterceptTouch伊芙nt(),让其回到true。

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    Log.i(TAG, "onInterceptTouchEvent: " + event.getAction() + " | 是否拦截:" + true);
    return true;//super.onInterceptTouchEvent(event);
}

测试log如下:

01-05 19:03:21.788 9733-9733/cn.codingblock.view I/Activity: dispatchTouchEvent: 0 | 分发事件
01-05 19:03:21.789 9733-9733/cn.codingblock.view I/——Layout: dispatchTouchEvent: 0 | 分发事件
01-05 19:03:21.789 9733-9733/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 0 | 是否拦截:true
01-05 19:03:21.789 9733-9733/cn.codingblock.view I/——Layout: onTouchEvent: 0 | 是否消耗事件:true
01-05 19:03:21.819 9733-9733/cn.codingblock.view I/Activity: dispatchTouchEvent: 2 | 分发事件
01-05 19:03:21.819 9733-9733/cn.codingblock.view I/——Layout: dispatchTouchEvent: 2 | 分发事件
01-05 19:03:21.819 9733-9733/cn.codingblock.view I/——Layout: onTouchEvent: 2 | 是否消耗事件:true
01-05 19:03:21.877 9733-9733/cn.codingblock.view I/Activity: dispatchTouchEvent: 1 | 分发事件
01-05 19:03:21.877 9733-9733/cn.codingblock.view I/——Layout: dispatchTouchEvent: 1 | 分发事件
01-05 19:03:21.877 9733-9733/cn.codingblock.view I/——Layout: onTouchEvent: 1 | 是否消耗事件:true

示例五、给View绑定OnTouchListener和OnClickListener监听器。

在伊夫ntDispatchActivity的onCreate()方法里面添加如下代码,并将伊芙ntDispatchLinearLayout和伊芙ntDispatchTestView的各艺术的再次回到值都还原成示例一中的状态。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_event_dispatch);
    edtv_test = ViewUtils.find(this, R.id.edtv_test);
    edll_test = ViewUtils.find(this, R.id.edll_test);

    edtv_test.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // 为了log显示的层次更加清晰,这里的TAG使用View的TAG
            Log.i("————View", "onTouch: 返回 " + false);
            return false;
        }
    });

    edtv_test.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // 为了log显示的层次更加清晰,这里的TAG使用View的TAG
            Log.i("————View", "onClick: ");
        }
    });
}

测试log如下:

01-06 19:35:07.563 6737-6737/cn.codingblock.view I/Activity: dispatchTouchEvent: 0 | 分发事件
01-06 19:35:07.563 6737-6737/cn.codingblock.view I/——Layout: dispatchTouchEvent: 0 | 分发事件
01-06 19:35:07.563 6737-6737/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 0 | 是否拦截:false
01-06 19:35:07.563 6737-6737/cn.codingblock.view I/————View: dispatchTouchEvent: 0 | 分发事件
01-06 19:35:07.563 6737-6737/cn.codingblock.view I/————View: onTouch: 返回 false
01-06 19:35:07.563 6737-6737/cn.codingblock.view I/————View: onTouchEvent: 0 | 是否消耗事件:true

01-06 19:35:07.573 6737-6737/cn.codingblock.view I/Activity: dispatchTouchEvent: 2 | 分发事件
01-06 19:35:07.573 6737-6737/cn.codingblock.view I/——Layout: dispatchTouchEvent: 2 | 分发事件
01-06 19:35:07.573 6737-6737/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 2 | 是否拦截:false
01-06 19:35:07.573 6737-6737/cn.codingblock.view I/————View: dispatchTouchEvent: 2 | 分发事件
01-06 19:35:07.574 6737-6737/cn.codingblock.view I/————View: onTouch: 返回 false
01-06 19:35:07.574 6737-6737/cn.codingblock.view I/————View: onTouchEvent: 2 | 是否消耗事件:true

01-06 19:35:07.673 6737-6737/cn.codingblock.view I/Activity: dispatchTouchEvent: 1 | 分发事件
01-06 19:35:07.674 6737-6737/cn.codingblock.view I/——Layout: dispatchTouchEvent: 1 | 分发事件
01-06 19:35:07.674 6737-6737/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 1 | 是否拦截:false
01-06 19:35:07.674 6737-6737/cn.codingblock.view I/————View: dispatchTouchEvent: 1 | 分发事件
01-06 19:35:07.674 6737-6737/cn.codingblock.view I/————View: onTouch: 返回 false
01-06 19:35:07.674 6737-6737/cn.codingblock.view I/————View: onTouchEvent: 1 | 是否消耗事件:true
01-06 19:35:07.704 6737-6737/cn.codingblock.view I/————View: onClick: 

然后再上边修改代码,让onTouch()方法消耗事件,约等于回来true,再观望log:

edtv_test.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // 为了log显示的层次更加清晰,这里的TAG使用View的TAG
        Log.i("————View", "onTouch: 返回 " + false);
        return false;
    }
});

log如下:

01-07 11:03:55.411 2757-2757/cn.codingblock.view I/Activity: dispatchTouchEvent: 0 | 分发事件
01-07 11:03:55.412 2757-2757/cn.codingblock.view I/——Layout: dispatchTouchEvent: 0 | 分发事件
01-07 11:03:55.412 2757-2757/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 0 | 是否拦截:false
01-07 11:03:55.412 2757-2757/cn.codingblock.view I/————View: dispatchTouchEvent: 0 | 分发事件
01-07 11:03:55.412 2757-2757/cn.codingblock.view I/————View: onTouch: 返回 true

01-07 11:03:55.542 2757-2757/cn.codingblock.view I/Activity: dispatchTouchEvent: 2 | 分发事件
01-07 11:03:55.542 2757-2757/cn.codingblock.view I/——Layout: dispatchTouchEvent: 2 | 分发事件
01-07 11:03:55.542 2757-2757/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 2 | 是否拦截:false
01-07 11:03:55.542 2757-2757/cn.codingblock.view I/————View: dispatchTouchEvent: 2 | 分发事件
01-07 11:03:55.542 2757-2757/cn.codingblock.view I/————View: onTouch: 返回 true

01-07 11:03:55.560 2757-2757/cn.codingblock.view I/Activity: dispatchTouchEvent: 1 | 分发事件
01-07 11:03:55.560 2757-2757/cn.codingblock.view I/——Layout: dispatchTouchEvent: 1 | 分发事件
01-07 11:03:55.560 2757-2757/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 1 | 是否拦截:false
01-07 11:03:55.560 2757-2757/cn.codingblock.view I/————View: dispatchTouchEvent: 1 | 分发事件
01-07 11:03:55.560 2757-2757/cn.codingblock.view I/————View: onTouch: 返回 true

从log中大家可以看来:

  • 为View绑定的OnTouchListener中的onTouch()方法是事先于View的onTouch伊芙nt()方法执行的。倘若在onTouch()消耗了事件(再次回到true),那么事件将不在传递给onTouch伊夫nt()方法,最后也不会调用onClick()方法。
  • 为View绑定的OnClickListener中的onClick()方法优先级最低,是在一切事件流停止后才会被调用,约等于急需经过手指的按下–抬起那些进度才会触发onClick()方法。

示例五、给View绑定OnTouchListener和OnClickListener监听器。

在伊夫ntDispatchActivity的onCreate()方法里面添加如下代码,并将EventDispatchLinearLayout和伊夫ntDispatchTestView的各艺术的重返值都还原成示例一中的状态。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_event_dispatch);
    edtv_test = ViewUtils.find(this, R.id.edtv_test);
    edll_test = ViewUtils.find(this, R.id.edll_test);

    edtv_test.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // 为了log显示的层次更加清晰,这里的TAG使用View的TAG
            Log.i("————View", "onTouch: 返回 " + false);
            return false;
        }
    });

    edtv_test.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // 为了log显示的层次更加清晰,这里的TAG使用View的TAG
            Log.i("————View", "onClick: ");
        }
    });
}

测试log如下:

01-06 19:35:07.563 6737-6737/cn.codingblock.view I/Activity: dispatchTouchEvent: 0 | 分发事件
01-06 19:35:07.563 6737-6737/cn.codingblock.view I/——Layout: dispatchTouchEvent: 0 | 分发事件
01-06 19:35:07.563 6737-6737/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 0 | 是否拦截:false
01-06 19:35:07.563 6737-6737/cn.codingblock.view I/————View: dispatchTouchEvent: 0 | 分发事件
01-06 19:35:07.563 6737-6737/cn.codingblock.view I/————View: onTouch: 返回 false
01-06 19:35:07.563 6737-6737/cn.codingblock.view I/————View: onTouchEvent: 0 | 是否消耗事件:true

01-06 19:35:07.573 6737-6737/cn.codingblock.view I/Activity: dispatchTouchEvent: 2 | 分发事件
01-06 19:35:07.573 6737-6737/cn.codingblock.view I/——Layout: dispatchTouchEvent: 2 | 分发事件
01-06 19:35:07.573 6737-6737/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 2 | 是否拦截:false
01-06 19:35:07.573 6737-6737/cn.codingblock.view I/————View: dispatchTouchEvent: 2 | 分发事件
01-06 19:35:07.574 6737-6737/cn.codingblock.view I/————View: onTouch: 返回 false
01-06 19:35:07.574 6737-6737/cn.codingblock.view I/————View: onTouchEvent: 2 | 是否消耗事件:true

01-06 19:35:07.673 6737-6737/cn.codingblock.view I/Activity: dispatchTouchEvent: 1 | 分发事件
01-06 19:35:07.674 6737-6737/cn.codingblock.view I/——Layout: dispatchTouchEvent: 1 | 分发事件
01-06 19:35:07.674 6737-6737/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 1 | 是否拦截:false
01-06 19:35:07.674 6737-6737/cn.codingblock.view I/————View: dispatchTouchEvent: 1 | 分发事件
01-06 19:35:07.674 6737-6737/cn.codingblock.view I/————View: onTouch: 返回 false
01-06 19:35:07.674 6737-6737/cn.codingblock.view I/————View: onTouchEvent: 1 | 是否消耗事件:true
01-06 19:35:07.704 6737-6737/cn.codingblock.view I/————View: onClick: 

然后再上边修改代码,让onTouch()方法消耗事件,约等于重临true,再观望log:

edtv_test.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // 为了log显示的层次更加清晰,这里的TAG使用View的TAG
        Log.i("————View", "onTouch: 返回 " + false);
        return false;
    }
});

log如下:

01-07 11:03:55.411 2757-2757/cn.codingblock.view I/Activity: dispatchTouchEvent: 0 | 分发事件
01-07 11:03:55.412 2757-2757/cn.codingblock.view I/——Layout: dispatchTouchEvent: 0 | 分发事件
01-07 11:03:55.412 2757-2757/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 0 | 是否拦截:false
01-07 11:03:55.412 2757-2757/cn.codingblock.view I/————View: dispatchTouchEvent: 0 | 分发事件
01-07 11:03:55.412 2757-2757/cn.codingblock.view I/————View: onTouch: 返回 true

01-07 11:03:55.542 2757-2757/cn.codingblock.view I/Activity: dispatchTouchEvent: 2 | 分发事件
01-07 11:03:55.542 2757-2757/cn.codingblock.view I/——Layout: dispatchTouchEvent: 2 | 分发事件
01-07 11:03:55.542 2757-2757/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 2 | 是否拦截:false
01-07 11:03:55.542 2757-2757/cn.codingblock.view I/————View: dispatchTouchEvent: 2 | 分发事件
01-07 11:03:55.542 2757-2757/cn.codingblock.view I/————View: onTouch: 返回 true

01-07 11:03:55.560 2757-2757/cn.codingblock.view I/Activity: dispatchTouchEvent: 1 | 分发事件
01-07 11:03:55.560 2757-2757/cn.codingblock.view I/——Layout: dispatchTouchEvent: 1 | 分发事件
01-07 11:03:55.560 2757-2757/cn.codingblock.view I/——Layout: onInterceptTouchEvent: 1 | 是否拦截:false
01-07 11:03:55.560 2757-2757/cn.codingblock.view I/————View: dispatchTouchEvent: 1 | 分发事件
01-07 11:03:55.560 2757-2757/cn.codingblock.view I/————View: onTouch: 返回 true

从log中我们得以观望:

  • 为View绑定的OnTouchListener中的onTouch()方法是优先于View的onTouch伊夫nt()方法执行的。如若在onTouch()消耗了轩然大波(重临true),那么事件将不在传递给onTouch伊芙nt()方法,最后也不会调用onClick()方法。
  • 为View绑定的OnClickListener中的onClick()方法优先级最低,是在方方面面事件流甘休后才会被调用,约等于要求经过手指的按下–抬起这么些进程才会触发onClick()方法。

小结

为了更好的了解,可以把事件流看成是一队人,把ACTION_DOWN类型看做探路人,探路人按规定的路线先走三遍,直到走到View的onTouch伊夫nt那里,若是onTouch伊芙nt重回true,可见晓成此路通,后续部队可以过来。如若回到false,能够了解成此路不通,然后探路人再到Layout(ViewGroup)的onTouch伊夫nt中问路通不通,借使通的话后续部队就不要再去View那里了,直接到ViewGroup那来就足以了。而只要ViewGroup那里路也短路,那么探路人就只好去Activity的onTouch伊夫nt这里了,后续部队也直接去Activity的onTouch伊夫nt那里就可以了。


终极想说的是,本连串作品为博主对Android知识展开双重梳理,查缺补漏的就学进程,一方面是对协调忘记的东西加以复习重新精晓,另一方面相信在重新学习的进度中定会有巨大的新取得,就算你也有跟自家同一的想法,不妨关注小编一块儿学学,相互商量,共同提升!

参考文献:

  • 《Android开发格局探索》

小结

为了更好的知晓,可以把事件流看成是一队人,把ACTION_DOWN类型看做探路人,探路人按规定的线路先走四次,直到走到View的onTouch伊夫nt那里,若是onTouch伊芙nt重回true,可分晓成此路通,后续部队可以回复。如若回去false,可以知晓成此路不通,然后探路人再到Layout(ViewGroup)的onTouch伊夫nt中问路通不通,即使通的话后续部队就毫无再去View这里了,直接到ViewGroup那来就足以了。而借使ViewGroup那里路也打断,那么探路人就只可以去Activity的onTouch伊芙nt那里了,后续部队也一贯去Activity的onTouch伊夫nt那里就可以了。


末段想说的是,本系列文章为博主对Android知识展开双重梳理,查缺补漏的读书进度,一方面是对协调忘记的东西加以复习重新领会,另一方面相信在重新学习的长河中定会有宏伟的新拿到,假诺您也有跟自身一样的想法,不妨关注自个儿二头读书,互相商讨,共同提高!

参考文献:

  • 《Android开发格局探索》

相关文章