【轉載】Android的事件分發(dispatchTouchEvent),攔截(onInterceptTouchEvent)與處理(onTouchEvent)

出處:https://blog.csdn.net/caifengyao/article/details/65437695html

在Android中,View的結構是樹狀的,因此,當觸發觸摸事件的時候,其事件傳遞也是從上之下一層層的傳遞。下面咱們結合例子來一點點進行分析。java

首先,咱們須要瞭解事件處理中的幾個方法:ide

一、在ViewGroup中,事件分爲dispatchTouchEvent(事件的分發),onInterceptTouchEvent(事件的攔截),onTouchEvent(事件的處理)。post

二、在View中,事件分爲dispatchTouchEvent(事件的分發),onTouchEvent(事件的處理)。spa

下面是demo的界面結構,它是由兩個自定義的ViewGroup和一個自定義的View組成,並分別重寫了它們的以上幾個方法。.net


其中MyViewGroupA代碼以下:3d

 

public class MyViewGroupA extends LinearLayout {
    public MyViewGroupA(Context context) {
        super(context);
    }

    public MyViewGroupA(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.i("MyViewGroupA","dispatchTouchEvent_ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.i("MyViewGroupA","dispatchTouchEvent_ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.i("MyViewGroupA","dispatchTouchEvent_ACTION_UP");
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.i("MyViewGroupA","onInterceptTouchEvent_ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.i("MyViewGroupA","onInterceptTouchEvent_ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.i("MyViewGroupA","onInterceptTouchEvent_ACTION_UP");
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.i("MyViewGroupA","onTouchEvent_ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.i("MyViewGroupA","onTouchEvent_ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.i("MyViewGroupA","onTouchEvent_ACTION_UP");
                break;
        }
        return super.onTouchEvent(event);
    }
}
MyViewGroupB代碼以下:

 

 

public class MyViewGroupB extends LinearLayout {
    public MyViewGroupB(Context context) {
        super(context);
    }

    public MyViewGroupB(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.i("MyViewGroupB","dispatchTouchEvent_ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.i("MyViewGroupB","dispatchTouchEvent_ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.i("MyViewGroupB","dispatchTouchEvent_ACTION_UP");
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.i("MyViewGroupB","onInterceptTouchEvent_ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.i("MyViewGroupB","onInterceptTouchEvent_ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.i("MyViewGroupB","onInterceptTouchEvent_ACTION_UP");
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.i("MyViewGroupB","onTouchEvent_ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.i("MyViewGroupB","onTouchEvent_ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.i("MyViewGroupB","onTouchEvent_ACTION_UP");
                break;
        }
        return super.onTouchEvent(event);
    }
}
MyView代碼以下:

 

 

public class MyView extends View {
    public MyView(Context context) {
        super(context);
    }

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.i("MyView","dispatchTouchEvent_ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.i("MyView","dispatchTouchEvent_ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.i("MyView","dispatchTouchEvent_ACTION_UP");
                break;
        }
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.i("MyView","onTouchEvent_ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.i("MyView","onTouchEvent_ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.i("MyView","onTouchEvent_ACTION_UP");
                break;
        }
        return super.onTouchEvent(event);
    }
}

咱們說過,事件傳遞是由上到下的,因此最外層的View首先對事件進行操做。而咱們最外層是Activity,因此事件也是從這裏開始。
Activity代碼以下:

 

 

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.i("Activity","dispatchTouchEvent_ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.i("Activity","dispatchTouchEvent_ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.i("Activity","dispatchTouchEvent_ACTION_UP");
                break;
        }
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.i("Activity","onTouchEvent_ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.i("Activity","onTouchEvent_ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.i("Activity","onTouchEvent_ACTION_UP");
                break;
        }
        return super.onTouchEvent(event);
    }
}

如今咱們經過觸摸MyView開始進行分析。雖然dispatchTouchEvent是事件開始的第一步,可是在開發中,咱們一般不多改寫它,因此咱們下面只討論其餘兩個方法。

 

一、對以上方法均不做處理,都返回super。這意味着咱們既不攔截,也不消費。htm

你們看輸出結果:blog

I/Activity: dispatchTouchEvent_ACTION_DOWN事件


I/MyViewGroupA: dispatchTouchEvent_ACTION_DOWN
I/MyViewGroupA: onInterceptTouchEvent_ACTION_DOWN


I/MyViewGroupB: dispatchTouchEvent_ACTION_DOWN
I/MyViewGroupB: onInterceptTouchEvent_ACTION_DOWN


I/MyView: dispatchTouchEvent_ACTION_DOWN
I/MyView: onTouchEvent_ACTION_DOWN


I/MyViewGroupB: onTouchEvent_ACTION_DOWN
I/MyViewGroupA: onTouchEvent_ACTION_DOWN
I/Activity: onTouchEvent_ACTION_DOWN


I/Activity: dispatchTouchEvent_ACTION_MOVE
I/Activity: onTouchEvent_ACTION_MOVE


I/Activity: dispatchTouchEvent_ACTION_UP
I/Activity: onTouchEvent_ACTION_UP

結合輸出結果,咱們能夠總結出如下的結論:

  
結合流程圖,不難發現,若是我對事件既不攔截,也不消費,當觸發ACTION_DOWN的時候,事件會通過Activity——MyViewGroupA——MyViewGroupB——MyView一層層的向下進行dispatchTouchEvent(分發)—onInterceptTouchEvent(攔截)調用。當到達最底層MyView後,開始觸發消費操做,由於我均不消費,ACTION_DOWN將由底層一層層向上冒,移交上層處理。當抵達最上層Activity後,說明下層均不消費,以後觸發的ACTION_MOVE和ACTION_UP將再也不向下層分發傳遞,直接交由Activity分發給本身進行處理。

二、咱們將MyVIewGroupB的onInterceptTouchEvent返回值改成true,其餘均是super。這意味着僅僅MyViewGroupB進行事件攔截,但均無消費

輸出結果以下:

I/Activity: dispatchTouchEvent_ACTION_DOWN


I/MyViewGroupA: dispatchTouchEvent_ACTION_DOWN
I/MyViewGroupA: onInterceptTouchEvent_ACTION_DOWN


I/MyViewGroupB: dispatchTouchEvent_ACTION_DOWN
I/MyViewGroupB: onInterceptTouchEvent_ACTION_DOWN


I/MyViewGroupB: onTouchEvent_ACTION_DOWN
I/MyViewGroupA: onTouchEvent_ACTION_DOWN
I/Activity: onTouchEvent_ACTION_DOWN


I/Activity: dispatchTouchEvent_ACTION_MOVE
I/Activity: onTouchEvent_ACTION_MOVE


I/Activity: dispatchTouchEvent_ACTION_UP
I/Activity: onTouchEvent_ACTION_UP

結合輸出結果,總結以下:


當觸發ACTION_DOWN的時候,事件依然是從Activity開始一層層向下傳遞,當傳遞到MyViewGroupB時,由於進行了事件攔截,因此執行完onInterceptTouchEvent後再也不向下傳遞,而是直接交由MyViewGroupB的onTouchEvent進行消費處理。因爲咱們是隻攔截,不消費,因此事件向上傳遞,交由上層處理,最終回到Activity。以後觸發的ACTION_MOVE和ACTION_UP也再也不向下傳遞,直接交由Activity分發給本身處理。

三、咱們仍是將MyViewGroupB的onInterceptTouchEvent返回super,可是將他的onTouchEvent返回true。這意味着咱們不攔截,可是由MyViewGroupB進行事件處理。

輸出結果以下:

I/Activity: dispatchTouchEvent_ACTION_DOWN


I/MyViewGroupA: dispatchTouchEvent_ACTION_DOWN
I/MyViewGroupA: onInterceptTouchEvent_ACTION_DOWN


I/MyViewGroupB: dispatchTouchEvent_ACTION_DOWN
I/MyViewGroupB: onInterceptTouchEvent_ACTION_DOWN


I/MyView: dispatchTouchEvent_ACTION_DOWN
I/MyView: onTouchEvent_ACTION_DOWN
I/MyViewGroupB: onTouchEvent_ACTION_DOWN


I/Activity: dispatchTouchEvent_ACTION_MOVE
I/MyViewGroupA: dispatchTouchEvent_ACTION_MOVE
I/MyViewGroupA: onInterceptTouchEvent_ACTION_MOVE
I/MyViewGroupB: dispatchTouchEvent_ACTION_MOVE
I/MyViewGroupB: onTouchEvent_ACTION_MOVE


I/Activity: dispatchTouchEvent_ACTION_UP
I/MyViewGroupA: dispatchTouchEvent_ACTION_UP
I/MyViewGroupA: onInterceptTouchEvent_ACTION_UP
I/MyViewGroupB: dispatchTouchEvent_ACTION_UP
I/MyViewGroupB: onTouchEvent_ACTION_UP

結合輸出結果,總結以下:


能夠看出,當觸發ACTION_DOWN的時候,事件的分發傳遞過程和1的時候同樣,從Activity開始一層層向下傳遞,最終傳遞到最底層MyView,觸發消費操做,而後MyView將消費操做移交上層處理,而後到達MyViewGroupB的onTouchEvent,而且進行了消費處理,事件處理到此不在向上移交。當觸發ACTION_MOVE和ACTION_UP操做時,事件依然須要由Activity開始向下分發傳遞,可是當傳遞到MyViewGroupB後,因爲其消費了ACTION_DOWN,事件將再也不繼續向下分發,而是直接由MyViewGroupB分發給本身的onTouchEvent進行繼續處理。事件處理也再也不向上移交。

四、將MyViewGroupB的onInterceptTouchEvent和onTouchEvent的返回值均改成true。這意味着既攔截,又消費。

輸出結果以下:

I/Activity: dispatchTouchEvent_ACTION_DOWN


I/MyViewGroupA: dispatchTouchEvent_ACTION_DOWN
I/MyViewGroupA: onInterceptTouchEvent_ACTION_DOWN


I/MyViewGroupB: dispatchTouchEvent_ACTION_DOWN
I/MyViewGroupB: onInterceptTouchEvent_ACTION_DOWN


I/MyViewGroupB: onTouchEvent_ACTION_DOWN


I/Activity: dispatchTouchEvent_ACTION_MOVE
I/MyViewGroupA: dispatchTouchEvent_ACTION_MOVE
I/MyViewGroupA: onInterceptTouchEvent_ACTION_MOVE
I/MyViewGroupB: dispatchTouchEvent_ACTION_MOVE
I/MyViewGroupB: onTouchEvent_ACTION_MOVE


I/Activity: dispatchTouchEvent_ACTION_UP
I/MyViewGroupA: dispatchTouchEvent_ACTION_UP
I/MyViewGroupA: onInterceptTouchEvent_ACTION_UP
I/MyViewGroupB: dispatchTouchEvent_ACTION_UP
I/MyViewGroupB: onTouchEvent_ACTION_UP

結合輸出結果,總結以下:


當觸發ACTION_DOWN的時候,依然從Activity開始向下傳遞,當到達MyViewGroupB的是,由於在onInterceptTouchEvent進行了攔截操做,所以再也不繼續向下分發傳遞,而是交由MyViewGroupB的onTouchEvent進行處理消費。MyViewGroupB的onTouchEvent返回的是true,說明它決定對ACTION_DOWN進行處理,所以事件也就再也不移交上層處理。當觸發ACTION_MOVE和ACTION_UP的時候,事件仍是從Activity開始向下傳遞,當到達MyViewGroupB的時候,因爲以前進行了攔截操做,所以,MyViewGroupB直接將事件分發給本身的onTouchEvent進行處理,不在向下分發傳遞。事件處理也再也不向上層移交。

 

案例Demo下載地址:點擊打開連接

閱讀更多
相關文章
相關標籤/搜索