Android查缺补漏(View篇)–事件分发机制

每一日一本书,是试图用多少个小传说来论述那部书的剧情。并且附上自个儿的感受。希望能与大家一道分享。

事件分发机制是Android中万分主要的一个知识点,同时也是难点,相信到最近截止很多Android开发者对事件分发机制并没有1个卓殊系统的认识,当然也包含博主个人在内。恐怕在日常的开支工作中我们并没有发现到事件分发机制起到的作用,其实它是随时存在的只是我们不晓得而已,就像是一些滑行顶牛、点击事件之间的争辩等等大多是因为事件分发处理不当导致的。想起了博主大学时做过3个小品种,里面就出现了滑动冲突的标题,即便最终在网上一步步看着外人的课程也糊里糊涂的缓解了,但到底不知其所以然,那么前几日就让大家一起来深远的探赜索隐一下事件分发机制吗。

小编巴尔科姆·格拉德威尔,三个负有牙买加血统的德国人,《London客》的怪才,被《快集团》杂志称为“21世纪的Peter·德鲁克”,被《时代》杂志评为全世界最有影响力的9五人人选之一。他的小说《引爆点》、《决断2秒间》以及新作《异类》都创建了书市神话。

什么样是事件分发机制?

说了半天的风云分发机制那到底是个吗东西呢?我们不用把它想象的那么高深莫测,不要在思维上给本人设上阻碍,其实很不难精晓,博主的接头是:简单的讲,事件分发机制便是Android系统对事件传递进程规定的一种事件传递规则,事件都会奉公守法那一个规则举行分发传递。

在商讨事件分发机制在此以前,大家先来规定一下分析的手续,化整为零,种种击破:

  • 弄精晓分析目的:Motion伊夫nt。
  • 打听四个法子:dispatchTouch伊芙nt(Motion伊夫nt
    event)、onInterceptTouch伊夫nt(Motion
    event)、onTouch伊芙nt(Motion伊芙nt event)。
  • Motion伊夫nt事件的传递进程
  • 小结

本书重点介绍三种法则

▪ 个外人物法则

▪ 附着力法则

▪ 环境威力法则

MotionEvent

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

而点击操作触发Motion伊夫nt事件是贰个事件流或然说是二个事变系列,其出众的风云类型有如下两种:

  • MotionEvent.ACTION_DOWN:手指刚点下显示器时接触此类型。
  • MotionEvent.ACTION_MOVE:手指在荧屏上移步时会数次接触此类型。
  • MotionEvent.ACTION_UP:手指在显示屏上抬起时接触此类型。

要尤其注意的是,平常状态下贰个Motion伊夫nt事件类别包括2个 ACTION_DOWN
若干个 ACTION_MOVE 和 ACTION_UP
是一个一体化的轩然大波类别。(点下来立马抬起指头时,会只有 ACTION_DOWN 和
ACTION_UP,那也是三个全部的事件类别)

自己将以3个音乐家的有趣的事,向大家大饱眼福本书要点!

dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent

  • boolean dispatchTouchEvent (MotionEvent event):

分发事件,只要事件能传递到当前View就一定会调用此格局,其重返值是3个布尔类型表示是还是不是消耗事件。再次来到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()处理。

上文说了如此多仍旧不够具体,先用流程图大体说多美滋个上述多个章程的涉及,及调用流程,下文还会结合现实示例详细表明在事变分发传递中各样艺术的调用规则。

三者关系大体如下图:

图片 1

Motion伊夫nt事件传递进程

当手教导击显示屏发生3个Touch事件后,事件依据Activity->Window->View的逐一依次传递。

首先会传递给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大概又是2个ViewGroup,假若那样的话其传递流程同根View一样。无论根View的部下View是或不是ViewGroup,若是不阻拦事件,最终事件会传递到七个纯View的控件上。

当三个View(纯View控件)接收到事件后,也会调用其dispatchTouch伊夫nt(),然后在此方式内部会调用当前View的onTouch伊夫nt(),借使onTouch伊夫nt()再次来到true则象征要处理此事件。假设回去false表示不消耗事件,其顶头上司View的onTouch伊芙nt()将被调用,则事件流的存在延续部分不再传递到方今View,在一个事变流中也不会再调用当前View的dispatchTouch伊夫nt()。

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

▪ 个外人物法则

   你放屁是香的?

     
 在某国有个闻明的画画大师,画风大胆新颖,富有军事学思想,很多债权国国风大雅小雅的人都盼望以千金购买一副小说,能在温馨朋友圈子中炫耀,满足一下友好卑微的虚荣心;

     
一天,那名书法家引导协调的5虚岁外甥画别人生第③幅画,时期淘气孙子因为其实受不住枯燥的绘画,就把画纸上洒满颜料,然后用画笔在上头胡乱涂抹,那名美术师并从未发火,反而把这幅不称为画
的画收藏了四起,希望在20年后,能给协调回味下;

     某天小偷趁着美术师去旅游了,把这幅画悄悄的扒窃了;

   
 搞笑的事就此发生,社会上赫然有可信赖传出这是那名乐师的摩登力作,那副画价格须臾间被炒到了100w台币;

     就此在收藏界刮起一场龙卷风!

示例一,暗中同意景况下的风云传递流程

成立三个类,二个Activity、三个后续自LinearLayout的View,3个后续自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不消耗事件时的传递流程

接下去让地点的伊夫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的onTouch伊芙nt方法处理,而从log可以看到ViewGroup的onTouch伊芙nt暗许也不消耗事件,所以事件由提交Activity的onTouch伊夫nt方法处理,最后事件流的继承部分不再传递给ViewGroup和View,而是平昔传送给Activity的onTouch伊夫nt处理。

▪ 环境威力法则

   全国都在座谈!

150定律(Rule
Of150),即有名的“邓巴数字”,由英帝国浦项艺术学院的人类学家罗布in·Dunbar(罗布in
邓巴)建议。该定律依据猿猴的智力与对立互联网预计出:人类智慧将同意人类享有平安社交互联网的食指是145位,四舍五入大概是153位。

       
 依照地点说到150定律,各界职员纷纭被朋友影响只怕影响本身的心上人,而那幅画成为了四面八方、茶余饭后的热门话题!

         此刻那幅画被炒到了一亿日元!

       
 此刻那名音乐大师,和太太儿女正在度假,一个对讲机打来:“嘿,兄弟你近期画的那幅画已经被炒到了1亿欧元了!”

       画家:“……”

笔记奉上

图片 2

民用订阅号同学多多赏脸:

图片 3

书籍下载链接:http://pan.baidu.com/s/1o6OHUl0  提取密码:frhw

宣称:
全体pdf书籍源于网上收集,仅供就学和商量接纳,无其余生意目标,版权归原版的书文者或出版社全体,如有侵略您版权的,请提出,本人将即时勘误。

示例叁 、在示例二的底蕴上让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

示例五、给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()方法。

小结

为了更好的接头,能够把事件流看成是一队人,把ACTION_DOWN类型看做探路人,探路人按规定的路线先走2回,直到走到View的onTouch伊芙nt那里,如若onTouch伊芙nt重临true,可清楚成此路通,后续部队能够回复。假若回去false,能够明白成此路不通,然后探路人再到Layout(ViewGroup)的onTouch伊夫nt中问路通不通,要是通的话后续部队就绝不再去View那里了,间接到ViewGroup那来就能够了。而一旦ViewGroup那里路也短路,那么探路人就不得不去Activity的onTouch伊芙nt那里了,后续部队也平素去Activity的onTouch伊夫nt那里就足以了。


最后想说的是,本类别小说为博主对Android知识进行双重梳理,查缺补漏的上学进程,一方面是对协调忘记的事物加以复习重新通晓,另一方面相信在重新学习的长河中定会有光辉的新收获,假如您也有跟小编同样的想法,不妨关注自己联合读书,相互琢磨,共同进步!

参考文献:

  • 《Android开发方式探索》