• Android的事件分发(dispatchTouchEvent),拦截(onInterceptTouchEvent)与处理(onTouchEvent)


    在Android中,View的结构是树状的,所以,当触发触摸事件的时候,其事件传递也是从上之下一层层的传递。下面我们结合例子来一点点进行分析。

    首先,我们需要了解事件处理中的几个方法:

    1、在ViewGroup中,事件分为dispatchTouchEvent(事件的分发),onInterceptTouchEvent(事件的拦截),onTouchEvent(事件的处理)。

    2、在View中,事件分为dispatchTouchEvent(事件的分发),onTouchEvent(事件的处理)。

    下面是demo的界面结构,它是由两个自定义的ViewGroup和一个自定义的View组成,并分别重写了它们的以上几个方法。

    其中MyViewGroupA代码如下:

    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是事件开始的第一步,但是在开发中,我们通常很少改写它,所以我们下面只讨论其他两个方法。
    1、对以上方法均不作处理,都返回super。这意味着我们既不拦截,也不消费。

    大家看输出结果:

    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分发给自己进行处理。

    2、我们将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分发给自己处理。

    3、我们还是将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进行继续处理。事件处理也不再向上移交。

    4、将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下载地址:点击打开链接

  • 相关阅读:
    [技术项目4]--接口自动化数据一览项目总结
    [技术项目3]--流量回放项目总结
    [技术项目2]--禅道项目报告统计总结
    [技术项目1]--数据工厂项目总结
    自动化测试常用的框架
    【vue】element-表单中,下拉框选中某个值后,同步更新其他输入框的值
    【vue】vue打包后,将dist文件夹自动压缩成生成dist.zip压缩包--filemanager-webpack-plugin
    译文:ovs+dpdk中的“vHost User NUMA感知”特性
    vue中防抖,节流的使用
    横向结构的树组件(leader-line-vue)
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/10014952.html
Copyright © 2020-2023  润新知