草率的旅行

       
上学期和姑娘打赌,即使他能在期先前时期末都考进大榜15名,我就带她去一个欢喜的城池观光。孙女期中第十三名,期末第九名,愿望是去海南看《快乐大本营》。这些心愿让自家很窘迫。因为【快本】不卖票,只有黄牛。我四处打探,一张票价从1200到1800不等。正赶上暑期黄金档,票价更是居高不下。后来,懂事的丫头决定改变行程,去方特旅游度假区玩。她说一张门票可以玩两个方特还富有,合算。

事件分发机制是Android中丰裕重要的一个知识点,同时也是难点,相信到近年来截止很多Android开发者对事件分发机制并从未一个这多少个系统的认识,当然也席卷博主个人在内。可能在平日的开支工作中大家并不曾发觉到事件分发机制起到的效率,其实它是时刻存在的只是我们不了解而已,就像有的滑行争持、点击事件期间的争执等等大多是因为事件分发处理不当导致的。想起了博主大学时做过一个小项目,里面就涌出了滑动争辨的问题,即便最后在网上一步步看着人家的学科也糊里糊涂的解决了,但毕竟不知其所以然,那么前几天就让我们一同来深远的探究一下风波分发机制吗。

     
全国有为数不少方特,我很忙,12岁的丫头温馨搜遍手机,决定去扬州。理由有二:

怎么是事件分发机制?

说了半天的风波分发机制这究竟是个吗东西吧?大家毫不把它想象的那么高深莫测,不要在思维上给协调设上阻碍,其实很容易精晓,博主的精晓是:简单的话,事件分发机制就是Android系统对事件传递过程规定的一种事件传递规则,事件都会遵照这些规则举行分发传递。

在商量事件分发机制此前,我们先来规定一下分析的步骤,化整为零,各样击破:

  • 弄精晓分析目的:Motion伊芙(Eve)nt。
  • 刺探多少个法子:dispatchTouch伊芙nt(Motion伊夫nt
    event)、onInterceptTouch伊芙nt(Motion
    event)、onTouch伊夫nt(Motion伊芙(Eve)nt event)。
  • Motion伊夫nt事件的传递过程
  • 小结

一、临沂有六个方特,可以痛快的玩

MotionEvent

实际上点击事件的散发过程就是对Motion伊夫(Eve)nt事件的分发过程,当用户点击操作按下后,Motion伊夫nt事件随后发出并透过自然的规则传递到指定的View上,这么些传递的进程和规则就是事件分发机制。

而点击操作触发Motion伊芙(Eve)nt事件是一个轩然大波流或者说是一个事件连串,其出色的事件类型有如下两种:

  • MotionEvent.ACTION_DOWN:手指刚点下屏幕时接触此类型。
  • MotionEvent.ACTION_MOVE:手指在屏幕上运动时会多次触及此类型。
  • MotionEvent.ACTION_UP:手指在屏幕上抬起时接触此类型。

要特别注意的是,平常状态下一个Motion伊夫nt事件连串包含一个 ACTION_DOWN
若干个 ACTION_MOVE 和 ACTION_UP
是一个完好的轩然大波体系。(点下来立马抬起指头时,会唯有 ACTION_DOWN 和
ACTION_UP,这也是一个完好无损的轩然大波体系)

二、离苏杭很近,可以去精晓一下美景。

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伊夫(Eve)nt()处理,假设上级View的onTouch伊夫(Eve)nt()如故重临false,那么事件将再交付上级的上级处理,以此类推,假诺各级View的onTouch伊芙nt()都不消耗事件,那么事件最后将送交Activity的onTouch伊夫(Eve)nt()处理。

上文说了如此多依然不够具体,先用流程图大体表达一个以上五个法子的涉及,及调用流程,下文还会组成具体示例详细说明在事变分发传递中各类艺术的调用规则。

三者关系大体如下图:

图片 1

     
我从不看其他攻略就允许了幼女的视角。就是这么一个马虎的支配竟成了当年假期最划算、幸福、奇妙、惬意的旅程。

Motion伊芙nt事件传递过程

当手指引击屏幕暴发一个Touch事件后,事件遵照Activity->Window->View的相继依次传递。

第一会传递给Activity的dispatchTouch伊芙nt(),在此形式内部会将由Window处理,接着事件会传递给根View,根View接收到事件后就会按照事件分发机制去处理事件。

根View在此地就是一个ViewGroup,它在承受到事件后会调用dispatchTouch伊夫(Eve)nt(),在此格局内部会通过onInterceptTouch伊夫nt()方法判断是否拦截事件,假若onInterceptTouch伊芙nt()重临true就代表它要阻止事件,事件将传递给当下ViewGroup的onTouch伊夫(Eve)nt()。假诺onInterceptTouch伊芙(Eve)nt()放回false就意味着它不阻拦事件,事件将传给其下属的View,调用下级View的dispatchTouch伊夫(Eve)nt()。

根View的下级View可能又是一个ViewGroup,如若这样的话其传递流程同根View一样。无论根View的下属View是不是ViewGroup,倘若不阻止事件,最后事件会传递到一个纯View的控件上。

当一个View(纯View控件)接收到事件后,也会调用其dispatchTouch伊芙(Eve)nt(),然后在此形式内部会调用当前View的onTouch伊芙nt(),假诺onTouch伊夫nt()重回true则意味着要处理此事件。假设回到false表示不消耗事件,其上边View的onTouch伊芙nt()将被调用,则事件流的接轨部分不再传递到当下View,在一个事件流中也不会再调用当前View的dispatchTouch伊芙(Eve)nt()。

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

经济小屋:

示例一,默认意况下的事件传递流程

创办3个类,一个Activity、一个延续自LinearLayout的View,一个接续自Button的View,不偏不倚写他们的dispatchTouch伊夫(Eve)nt()、onIntercepteTouch伊夫(Eve)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>

运转代码,点击伊芙(Eve)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伊芙(Eve)nt方法默认消耗事件。事件流的ACTION_DOWN类型Motion
伊夫nt率先到达View的onTouch伊夫(Eve)nt方法中,此时onTouch伊芙nt方法重返true,表示要处理事件,所以事件流的存续部分依然通过log中的流程到达了View的onTouch伊夫nt方法中。

     
住处是我从小猪app上搜的一家独立民宿。交通便民,到方特旅游度假区只有三站地的公交,打出租车也只是七八块钱。附近还有城市租赁电动汽车、共享单车。楼下不远就有一条商业街。

示例二、在示例一的底子上,让View的onTouch伊芙(Eve)nt不消耗事件时的传递流程

接下去让地方的伊芙ntDispatchTestView的onTouch伊夫(Eve)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伊夫(Eve)nt不消耗事件时,事件会付出ViewGroup的onTouch伊芙(Eve)nt方法处理,而从log可以看看ViewGroup的onTouch伊夫(Eve)nt默认也不消耗事件,所以事件由提交Activity的onTouch伊夫nt方法处理,最后事件流的延续部分不再传递给ViewGroup和View,而是直接传送给Activity的onTouch伊芙(Eve)nt处理。

图片 2

示例三、在示例二的底子上让ViewGroup消耗事件

修改伊芙ntDispatchLinearLayout的onTouch伊芙(Eve)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伊芙(Eve)nt,发现它不消耗事件,继而重返上级的ViewGroup的onTouch伊夫(Eve)nt中,发现它要消耗事件,事件流的后续部分就不在传递给View,也不在调用ViewGroup的onInterceptTouch伊芙nt方法,因为早已知晓View不处理事件,所以没必要再通过onInterceptTouchEvent方法来判断了。

小屋通透、简洁。入户智能电子门卡,一室一厅一厨一卫,设施健全。大家母女俩住富富有余,个人感觉客厅放张床,住五人都不以为挤。关键是这种安排价格仍旧然而百。

示例四、假设在ViewGroup的onInterceptTouch伊芙(Eve)nt中回到了true拦截了轩然大波,整个事件将不再传递给View而是直接交由ViewGroup的onTouch伊芙nt处理。

修改伊芙(Eve)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监听器。

在伊芙(Eve)ntDispatchActivity的onCreate()方法里面添加如下代码,并将伊芙(Eve)ntDispatchLinearLayout和伊夫(Eve)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伊芙(Eve)nt这里,假诺onTouch伊芙(Eve)nt重临true,可领悟成此路通,后续部队可以还原。如若回到false,可以知晓成此路不通,然后探路人再到Layout(ViewGroup)的onTouch伊芙nt中问路通不通,要是通的话后续部队就毫无再去View这里了,直接到ViewGroup这来就可以了。而倘若ViewGroup这里路也不通,那么探路人就只好去Activity的onTouch伊芙nt这里了,后续部队也一向去Activity的onTouch伊芙(Eve)nt这里就足以了。


最后想说的是,本系列随笔为博主对Android知识举行重复梳理,查缺补漏的就学过程,一方面是对自己忘记的东西加以复习重新领会,另一方面相信在重新学习的过程中定会有高大的新取得,如若您也有跟自身同一的想法,不妨关心自我一块上学,互相琢磨,共同提高!

参考文献:

  • 《Android开发模式探索》

图片 3

因为路程的原由,我要求早到几个钟头,他爽快地应承了。下飞机后从来和我们保持联系,为我们介绍揭阳美食和出游路线,帮大家查询坐什么样车便宜。每日游玩儿期间还关心我们到何地玩儿了;是不是跑丢了;需不需要指路。还主动请我们搭他的便车。不只是本人,抱有的网评都说她是系数的暖男帅哥。异乡他乡,有一个人关注,少了好多陌生,多了一份亲切。

奇妙方特:

       
方特旅游度假区由华强文化科技公司密切制作,是集主旨公园、宾馆餐饮、休闲娱乐于一体的综合性休闲旅游度假区。在湘潭有四大大旨公园。因为日子有限我们只去了梦乡王国、水上世界和东方神话。每个核心乐园都用了一整天的时光,玩的销魂。

        梦幻王国
真的是一座梦幻乐园。它将游乐元素与华夏价值观文化符号巧妙融合,融入顶尖的游玩科技。其中不少项目都是拒绝错过的,比如由4D效果打造的盘丝洞、生命之光、将来警察……其中的魔法学校最吸引人,我和孙女玩了一回。

    唯有将近才能真切感受到的效能

                            图不了!

还有故事唯美结尾震撼的水漫金山;室内过山车秦陵历险……。除了固定的分寸项目,我们还观看了炫酷的花式篮球,惊险又幽默的高台跳水,集舞美,灯光、武术、杂技为一身的重型舞台剧【猴王】。

图片 4

夜里还有舞台歌舞,烟花表演和花车表演。穿插其中的卡通人物和小孩子的互相更是给闺女带来许多愉快。

图片 5

图片 6

图片 7

     
水上世界汇聚了各种水上项目,不过很多项目外孙女不敢玩,比如大喇叭、小喇叭、高些的滑梯。不过我们依旧悠哉悠哉的玩了一次漂流。中间看了一场很吸引眼球的水上飞人表演,演员们踩着高高的水柱在半空中连续做出前后空翻等各个为难动作,引来一阵阵掌声和尖叫声。

     
东方神话是方特的四期工程,比起前几期更是的惊险刺激也进一步有东方神韵。我们首先逛了有中华特色的非遗小镇,里面商品价格合理,小小的买入了瞬间。没有看文成公主出嫁的上演就去找各种奇怪体验了,大家跟随女娲娘娘炼五彩石补天;和梁山伯祝英台一起感受千古蝶恋,和老牛一起见证牛郎织女的情爱,穿过地府体味灵魂之旅,站在森林飞龙下和上边的人一道大叫,在雷峰塔外感受跳楼机的惊悚……不过,孙女念兹在兹的双层木马被失去了,我的飞越河谷也没玩成,还有太多刺激的门类没敢尝试,只好留着不满了。

图片 8

图片来源网络

(丛林飞龙—木质过山车)

图片 9

图形源于网络

(雷峰塔——跳楼机)

想知道各样园的详细攻略唯有等下几期喽!

如意时光:

   
在每个方特游玩后的第二天,我和女儿都要趴在床上大半天用来休养生息。不愿意动的中午就点份汁浓味美的小笼包或笋丁烧麦。恢复生机体力的黄昏就手拉手去逛夜市和大排挡。随意找个摊位点份小龙虾,一边谈笑,一边享受人造夏风(哈哈,风扇而已)。重临时或许带回几份软糯香甜的蛋糕,或在邻近超市采购一堆零食、水果和姑娘一同打发夜晚时分。

   
遗憾的地点。除了四期的东头神话没有玩全,还有一期的喜形于色世界没有时间去,鸠兹古镇也离我们很近呀。只可以等下次了!

图片 10

图片源于网络

(鸠兹古镇)

即便有点细微遗憾,但这一次的泰州之行相对是幼女心中的欢喜记念。

    比较后来的日本首都迪士尼,个人认为方特更加的经济,也愈发人性化一些。