【转载】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下载地址:点击打开连接

阅读更多
相关文章
相关标签/搜索