Android查缺補漏(View篇)--事件分發機制

來源:互聯網
上載者:User

標籤:extends   pat   小結   操作   turn   事件流   apk   linear   xmlns   

事件分發機制是Android中非常重要的一個知識點,同時也是痛點,相信到目前為止很多Android開發人員對事件分發機制並沒有一個非常系統的認識,當然也包括博主個人在內。可能在平時的開發工作中我們並沒有意識到事件分發機制起到的作用,其實它是時刻存在的只是我們不知道而已,就像一些滑動衝突、點擊事件之間的衝突等等大多是因為事件分發處理不當導致的。想起了博主大學時做過一個小項目,裡面就出現了滑動衝突的問題,雖然最後在網上一步步看著別人的教程也糊裡糊塗的解決了,但終究不知其所以然,那麼今天就讓我們一起來深入的探索一下事件分發機制吧。

什麼是事件分發機制?

說了半天的事件分發機制那到底是個啥東西呢?我們不要把它想象的那麼高深莫測,不要在心理上給自己設上障礙,其實很容易理解,博主的理解是:簡單來說,事件分發機制就是Android系統對事件傳遞過程規定的一種事件路由規則,事件都會按照這個規則進行分發傳遞。

在研究事件分發機制之前,我們先來確定一下分析的步驟,化整為零,各個擊破:

  • 弄清楚分析目標:MotionEvent。
  • 瞭解三個方法:dispatchTouchEvent(MotionEvent event)、onInterceptTouchEvent(Motion event)、onTouchEvent(MotionEvent event)。
  • MotionEvent事件的傳遞過程
  • 小結
MotionEvent

其實點擊事件的分發過程就是對MotionEvent事件的分發過程,當使用者點擊操作按下後,MotionEvent事件隨即產生並通過一定的規則傳遞到指定的View上,這個傳遞的過程和規則就是事件分發機制。

而點擊操作觸發MotionEvent事件是一個事件流或者說是一個事件序列,其典型的事件類型有如下三種:

  • MotionEvent.ACTION_DOWN:手指剛點下螢幕時觸發此類型。
  • MotionEvent.ACTION_MOVE:手指在螢幕上移動時會多次觸發此類型。
  • MotionEvent.ACTION_UP:手指在螢幕上抬起時觸發此類型。

要特別注意的是,通常情況下一個MotionEvent事件序列包含一個 ACTION_DOWN 若干個 ACTION_MOVE 和 ACTION_UP 是一個完整的事件序列。(點下去立馬抬起手指時,會只有 ACTION_DOWN 和 ACTION_UP,這也是一個完整的事件序列)

dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent
  • boolean dispatchTouchEvent (MotionEvent event):

分發事件,只要事件能傳遞到當前View就一定會調用此方法,其傳回值是一個布爾類型表示是否消耗事件。返回true代表消耗事件,事件流的後續部分還會接著傳遞過來;返回false代表不消耗事件,事件流的後續部分就不再傳遞於此。

  • boolean onInterceptTouchEvent (MotionEvent ev):

此方法表示是否攔截MotionEvent事件,只有ViewGroup類型的控制項才有此方法。如果此方法返回true表示攔截事件,事件將傳遞給當前View的onTouchEvent()方法,而不再向其下級的View傳遞。如果此方法返回false表示不攔截事件,事件將傳遞給下級View的dispatchTouchEvent()。

  • boolean onTouchEvent (MotionEvent event):

此方法用來處理MotionEvent,傳回值表示是否消耗事件。返回true表示消耗事件,那麼事件流的後續部分還會傳遞過來;返回false表示不消耗事件,事件將交給上級View的onTouchEvent()處理,如果上級View的onTouchEvent()仍然返回false,那麼事件將再交給上級的上級處理,以此類推,如果各級View的onTouchEvent()都不消耗事件,那麼事件最終將交給Activity的onTouchEvent()處理。

上文說了這麼多還是不夠具體,先用流程圖大體說明一個以上三個方法的關係,及調用流程,下文還會結合具體樣本詳細說明在事件分發傳遞中各個方法的調用規則。

三者關係大體如:

MotionEvent事件傳遞過程

當手指點擊螢幕產生一個Touch事件後,事件按照Activity->Window->View的順序依次傳遞。

首先會傳遞給Activity的dispatchTouchEvent(),在此方法內部會將由Window處理,接著事件會傳遞給根View,根View接收到事件後就會按照事件分發機制去處理事件。

根View在這裡就是一個ViewGroup,它在接受到事件後會調用dispatchTouchEvent(),在此方法內部會通過onInterceptTouchEvent()方法判斷是否攔截事件,如果onInterceptTouchEvent()返回true就表示它要攔截事件,事件將傳遞給當前ViewGroup的onTouchEvent()。如果onInterceptTouchEvent()放回false就表示它不攔截事件,事件將傳給其下級的View,調用下級View的dispatchTouchEvent()。

根View的下級View可能又是一個ViewGroup,如果這樣的話其傳遞流程同根View一樣。無論根View的下級View是不是ViewGroup,如果不攔截事件,最終事件會傳遞到一個純View的控制項上。

當一個View(純View控制項)接收到事件後,也會調用其dispatchTouchEvent(),然後在此方法內部會調用當前View的onTouchEvent(),如果onTouchEvent()返回true則表示要處理此事件。如果返回false表示不消耗事件,其上級View的onTouchEvent()將被調用,則事件流的後續部分不再傳遞到當前View,在一個事件流中也不會再調用當前View的dispatchTouchEvent()。

接下來通過具體樣本來查看事件傳遞的流程:

樣本一,預設情況下的事件傳遞流程

建立3個類,一個Activity、一個繼承自LinearLayout的View,一個繼承自Button的View,並重寫他們的dispatchTouchEvent()、onIntercepteTouchEvent()、onTouchEvent(),三個類及布局檔案的代碼如下:

  • 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>

運行代碼,點擊EventDispatchTestView(黑色地區),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 | 是否攔截:false01-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 | 是否消耗事件:true01-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 | 是否攔截:false01-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 | 是否消耗事件:true01-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 | 是否攔截:false01-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的onInterceptTouchEvent方法預設是不攔截事件的,View的onTouchEvent方法預設消耗事件。事件流的ACTION_DOWN類型Motion
Event率先到達View的onTouchEvent方法中,此時onTouchEvent方法返回true,表示要處理事件,所以事件流的後續部分依然經過log中的流程到達了View的onTouchEvent方法中。

樣本二、在樣本一的基礎上,讓View的onTouchEvent不消耗事件時的傳遞流程

接下來讓上面的EventDispatchTestView的onTouchEvent返回false:

@Overridepublic 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 | 是否攔截:false01-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 | 是否消耗事件:false01-05 18:18:52.546 10771-10771/cn.codingblock.view I/——Layout: onTouchEvent: 0 | 是否消耗事件:false01-05 18:18:52.547 10771-10771/cn.codingblock.view I/Activity: onTouchEvent: 0 | 是否消耗事件:true01-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 | 是否消耗事件:true01-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的onTouchEvent不消耗事件時,事件會交給ViewGroup的onTouchEvent方法處理,而從log可以看出ViewGroup的onTouchEvent預設也不消耗事件,所以事件由交給Activity的onTouchEvent方法處理,最終事件流的後續部分不再傳遞給ViewGroup和View,而是直接傳遞給Activity的onTouchEvent處理。

樣本三、在樣本二的基礎上讓ViewGroup消耗事件

修改EventDispatchLinearLayout的onTouchEvent(),讓其返回true。

@Overridepublic 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 | 是否攔截:false01-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 | 是否消耗事件:false01-05 18:34:53.410 21169-21169/cn.codingblock.view I/——Layout: onTouchEvent: 0 | 是否消耗事件:true01-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 | 是否消耗事件:true01-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的onTouchEvent,發現它不消耗事件,繼而返回上級的ViewGroup的onTouchEvent中,發現它要消耗事件,事件流的後續部分就不在傳遞給View,也不在調用ViewGroup的onInterceptTouchEvent方法,因為已經知道View不處理事件,所以沒必要再通過onInterceptTouchEvent方法來判斷了。

樣本四、如果在ViewGroup的onInterceptTouchEvent中返回了true攔截了事件,整個事件將不再傳遞給View而是直接交由ViewGroup的onTouchEvent處理。

修改EventDispatchLinearLayout的onInterceptTouchEvent(),讓其返回true。

@Overridepublic 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 | 是否攔截:true01-05 19:03:21.789 9733-9733/cn.codingblock.view I/——Layout: onTouchEvent: 0 | 是否消耗事件:true01-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 | 是否消耗事件:true01-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監聽器。

在EventDispatchActivity的onCreate()方法裡面添加如下代碼,並將EventDispatchLinearLayout和EventDispatchTestView的各方法的傳回值都還原成樣本一中的狀態。

@Overrideprotected 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 | 是否攔截:false01-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: 返回 false01-06 19:35:07.563 6737-6737/cn.codingblock.view I/————View: onTouchEvent: 0 | 是否消耗事件:true01-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 | 是否攔截:false01-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: 返回 false01-06 19:35:07.574 6737-6737/cn.codingblock.view I/————View: onTouchEvent: 2 | 是否消耗事件:true01-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 | 是否攔截:false01-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: 返回 false01-06 19:35:07.674 6737-6737/cn.codingblock.view I/————View: onTouchEvent: 1 | 是否消耗事件:true01-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 | 是否攔截:false01-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: 返回 true01-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 | 是否攔截:false01-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: 返回 true01-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 | 是否攔截:false01-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的onTouchEvent()方法執行的。如果在onTouch()消耗了事件(返回true),那麼事件將不在傳遞給onTouchEvent()方法,最終也不會調用onClick()方法。
  • 為View綁定的OnClickListener中的onClick()方法優先順序最低,是在整個事件流結束後才會被調用,也就是需要經過手指的按下--抬起這個過程才會觸發onClick()方法。
小結

為了更好的理解,可以把事件流看成是一隊人,把ACTION_DOWN類型看做探路人,探路人按規定的線路先走一遍,直到走到View的onTouchEvent這裡,如果onTouchEvent返回true,可理解成此路通,後續部隊可以過來。如果返回false,可以理解成此路不通,然後探路人再到Layout(ViewGroup)的onTouchEvent中問路通不通,如果通的話後續部隊就不用再去View那裡了,直接到ViewGroup這來就可以了。而如果ViewGroup這裡路也不通,那麼探路人就只能去Activity的onTouchEvent那裡了,後續部隊也直接去Activity的onTouchEvent這裡就可以了。

最後想說的是,本系列文章為博主對Android知識進行再次梳理,查缺補漏的學習過程,一方面是對自己遺忘的東西加以複習重新掌握,另一方面相信在重新學習的過程中定會有巨大的新收穫,如果你也有跟我同樣的想法,不妨關注我一起學習,互相探討,共同進步!

參考文獻:

  • 《Android開發藝術探索》

Android查缺補漏(View篇)--事件分發機制

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.