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

事件分发机制是Android中分外紧要的一个知识点,同时也是难关,相信到如今甘休很多Android开发者对事件分发机制并不曾一个至极系统的认识,当然也包涵博主个人在内。可能在日常的开发工作中大家并不曾发现到事件分发机制起到的效应,其实它是每一天存在的只是大家不明白而已,如同有些滑行争执、点击事件之间的争辨等等大多是因为事件分发处理不当导致的。想起了博主大学时做过一个小品种,里面就涌出了滑动争辩的题目,尽管最终在网上一步步望着人家的科目也糊里糊涂的缓解了,但终究不知其所以然,那么明天就让大家一道来浓厚的追究一下轩然大波分发机制吗。

什么样是事件分发机制?

说了半天的风浪分发机制那究竟是个吗东西呢?我们绝不把它想象的那么高深莫测,不要在思想上给自己设上阻碍,其实很简单明白,博主的接头是:容易的话,事件分发机制就是Android系统对事件传递进度规定的一种事件传递规则,事件都会安分守己那些规则进行分发传递。

在探讨事件分发机制从前,大家先来规定一下剖析的步调,化整为零,种种击破:

  • 弄明白分析目的:Motion伊夫nt。
  • 通晓八个艺术:dispatchTouch伊夫(Eve)nt(Motion伊芙nt
    event)、onInterceptTouch伊芙nt(Motion
    event)、onTouch伊夫nt(Motion伊芙nt event)。
  • Motion伊芙(Eve)nt事件的传递进程
  • 小结

现今已经被研发出来的app见怪不怪,不过那五款app不容错过哦!

MotionEvent

其实点击事件的散发进度就是对Motion伊夫nt事件的分发进度,当用户点击操作按下后,Motion伊夫(Eve)nt事件随后发出并由此一定的条条框框传递到指定的View上,那个传递的进程和规则就是事件分发机制。

而点击操作触发Motion伊夫nt事件是一个事变流或者说是一个风云体系,其杰出的风浪类型有如下二种:

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

要尤其注意的是,日常状态下一个Motion伊芙(Eve)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伊夫(Eve)nt事件,只有ViewGroup类型的控件才有此方法。即使此方法重返true表示拦截事件,事件将传递给当下View的onTouch伊芙nt()方法,而不再向其下属的View传递。若是此形式重临false表示不阻止事件,事件将传递给下级View的dispatchTouch伊芙nt()。

  • boolean onTouchEvent (MotionEvent event):

此措施用来处理Motion伊芙nt,再次来到值表示是还是不是消耗事件。再次回到true表示消耗事件,那么事件流的再而三部分还会传送过来;重返false表示不消耗事件,事件将提交上级View的onTouch伊夫nt()处理,如若上边View的onTouch伊夫(Eve)nt()如故重临false,那么事件将再交给上级的上司处理,以此类推,即便各级View的onTouch伊芙nt()都不消耗事件,那么事件结尾将交由Activity的onTouch伊芙nt()处理。

上文说了那样多依旧不够具体,先用流程图大体说贝拉米(Bellamy)个上述多少个措施的关系,及调用流程,下文还会构成现实示例详细表明在事件分发传递中相继艺术的调用规则。

三者关系大体如下图:

图片 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伊夫nt()。倘诺onInterceptTouch伊芙nt()放回false就意味着它不阻碍事件,事件将传给其下属的View,调用下级View的dispatchTouch伊芙(Eve)nt()。

根View的下属View可能又是一个ViewGroup,倘诺那样的话其传递流程同根View一样。无论根View的属下View是否ViewGroup,假诺不阻碍事件,最后事件会传送到一个纯View的控件上。

当一个View(纯View控件)接收到事件后,也会调用其dispatchTouch伊夫nt(),然后在此办法内部会调用当前View的onTouch伊芙(Eve)nt(),如若onTouch伊夫(Eve)nt()返回true则意味着要处理此事件。如若回到false表示不消耗事件,其上级View的onTouch伊夫(Eve)nt()将被调用,则事件流的继续部分不再传递到当前View,在一个风云流中也不会再调用当前View的dispatchTouch伊芙nt()。

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

种子习惯

示例一,默许情形下的事件传递流程

成立3个类,一个Activity、一个连续自LinearLayout的View,一个接续自Button的View,仁同一视写他们的dispatchTouch伊夫(Eve)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>

运转代码,点击伊芙(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伊芙nt不消耗事件时,事件会付给ViewGroup的onTouch伊芙nt方法处理,而从log可以看看ViewGroup的onTouch伊芙(Eve)nt默认也不消耗事件,所以事件由提交Activity的onTouch伊芙(Eve)nt方法处理,最后事件流的存续部分不再传递给ViewGroup和View,而是间接传送给Activity的onTouch伊芙nt处理。

俺们都曾不甘如此过完此生。

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

修改伊夫(Eve)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伊芙nt中,发现它要费用事件,事件流的存续部分就不在传递给View,也不在调用ViewGroup的onInterceptTouch伊夫(Eve)nt方法,因为早已精晓View不处理事件,所以没要求再通过onInterceptTouch伊夫(Eve)nt方法来判定了。

那么现在,通过种子习惯恐怕可以让您的生存暴发多少的改动。

示例四、即便在ViewGroup的onInterceptTouch伊芙nt中回到了true拦截了轩然大波,整个事件将不再传递给View而是直接交由ViewGroup的onTouch伊夫(Eve)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监听器。

在伊芙(Eve)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伊芙(Eve)nt()方法,最终也不会调用onClick()方法。
  • 为View绑定的OnClickListener中的onClick()方法优先级最低,是在整整事件流截止后才会被调用,也就是索要通过手指的按下–抬起这一个进度才会触发onClick()方法。

斯洛伐克语流利说

小结

为了更好的知晓,可以把事件流看成是一队人,把ACTION_DOWN类型看做探路人,探路人按规定的路线先走三回,直到走到View的onTouch伊芙nt这里,纵然onTouch伊夫(Eve)nt再次回到true,可见晓成此路通,后续部队可以还原。如若回到false,可以通晓成此路不通,然后探路人再到Layout(ViewGroup)的onTouch伊芙(Eve)nt中问路通不通,倘诺通的话后续部队就不要再去View那里了,直接到ViewGroup那来就足以了。而一旦ViewGroup那里路也短路,那么探路人就不得不去Activity的onTouch伊芙nt那里了,后续部队也一向去Activity的onTouch伊夫nt那里就可以了。


末段想说的是,本系列作品为博主对Android知识举办再度梳理,查缺补漏的读书过程,一方面是对友好忘记的东西加以复习重新驾驭,另一方面相信在重新学习的长河中定会有宏伟的新取得,假若你也有跟自己同一的想法,不妨关怀自身一块念书,相互探究,共同升高!

参考文献:

  • 《Android开发方式探索》

这是一款好玩又幽默的俄语口语学习运用,可以看视频英剧学马耳他语,跟着原片玩趣味配音,还有详细的口音讲解,学习资料相当丰裕,课程内容覆盖日常对话,商务职场,旅行出游,高校生活等各样气象。

BBC

BBC双语阿拉伯语听力操练软件,每一天推荐BBC双语音讯。提供各样乌克兰语听力和英文音讯资讯,从经济音讯到生存科学技术,资源足够,词汇、语经济学习等听力数据周详,是一个提供杰出的德语听力磨炼播放器,支持重点词汇学习,辅助字号设置和中文呈现。

DAKA

[零压力口语陶冶场]一说拉脱维亚语就狼狈,一见到歪果仁就冷场。你要求一个零顾虑、不为难、永远不冷场的意大利共和国语口语磨炼场。学好口语,练是王道!海外伙伴真人语音提问,发音语调真实,可随时回看并查看文字提醒,自行决定回答节奏,听力口语同步升高,选用时下流行的、具有争议的、脑洞大到没有界限的题目,才是DAKA会问您的问题。

可汗大学

经过视频和兼具深度的小说并包含数学、科学、经济等科目,甚至人文医学科等。无论你是学生、教授、在家自修、校长、重回课堂的大人,或者是个温馨的外星人,只想学学一下地球生物协会一可汗高校将为你免费提供你要求的资料和资源。

中国大学mooc

在此间,每一个有意愿提高自己的人都足以免费获取优质的高等教育资源。丰硕的名校名师课程,来自985大学的上乘课程,从基础科学到经济学艺术、历史学历史到工程技术、经管管工学到农林医药,内容周密,完全免费。

乐乎精晓课

以此应该一大半人都相比精晓了,天涯论坛旗下的良知好应用,下面有海量名校课程,提供来自世界一级名校的两干余集精品录像课程,内容包蕴人文、军事学、数理、心情、经济等世界,资源格外丰盛。

藏书馆

那是提供书友之间相互借阅的一个阳台,可以免费借阅,自己也得以上传书籍,并且在看书时能够开展剪辑和写笔记,一个相当好的开卷APP。

随手记

那是一个挺便宜的记账APP,里面种种作用也越发齐全,平常总感到钱不了解花哪了,可以用这么些APP记录平日的一对成本,看看自己每个月,甚至年年钱花了有些,都花哪了,方便好用,最主要的是不耽误时间。

活动行

本条APP首即使让大千世界精晓和发现部分同城进行的运动,可以去报名出席,而且有过多活动都是免费的啊。

给大家种草了一波~

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图