浅析android事件分发机制

我觉得android中的事件分发机制的懵懂期应该是Listview中对于item的点击和长按事件,那个时候知道item的长按事件是返回boolean值的方法,我们知道要把那个false改成true。。。这样我们长按事件结束后就不会再继续触发点击事件了

一、引言

1、关于listview中的item点击事件以及item长按事件的引入(本来是想跟onClick事件一起的,然后就发现一个问题了):Don’t call setOnClickListener for an AdapterView. You probably want setOnItemClickListener instead,就是说android设计中不允许给类似listview的控件(AdapterView)直接写onClick事件。

//listview中的item点击事件
lvProduct.setOnItemClickListener(new AdapterView.OnItemClickListener() {
           @Override
           public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
               Log.e(Tag,"onItemClick");
           }
       });

//listview中的item长按事件
        lvProduct.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
                Log.e(Tag,"onItemLongClick");
                return false;
            }
        });

我们通过log打印下,在onItemLongClick分别返回false以及true的情况下:

1).返回false的情况下长按item

这里写图片描述

2).返回true的情况下长按item
这里写图片描述

我们会发现我们执行长按操作的时候应该是先点击了这个item然后不动持续一段时间。其实这跟我们的事件消费很相似,如果在长按事件下返回了true,那么表示这个事件被消费了,然后就不会在继续传递这个动作了。但是如果返回了false,表示这个事件动作还会继续传递,因为你长按item的时候也是点击了这个item,所以会执行onItemClick事件。

2、再比如,我们再一个Textview上写onClick事件以及onTouch事件做个试验:

//点击事件
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                Log.w(Tag,"onClick");
            }
        });

        //触摸事件
        textView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                Log.w(Tag,"onTouch");
                return false;
            }
        });

我们通过log打印下在onTouch事件中返回true和false的两种情况:

1)返回false

正常点击
这里写图片描述

正常点击加移动
这里写图片描述

2)返回true
正常点击:
这里写图片描述

正常点击加移动
这里写图片描述

同理我们会发现textview中的现象与我们之前验证的基本吻合,如果返回true表示事件被消费,将不再继续传递这个动作,如果返回false表示这个动作将会继续传递。但是为什么onTouch事件会执行两次或者多次呢,这是因为执行onTouch事件会进行3种基本的操作ACTION_DOWN(手指按下),ACTION_UP(手指抬起),ACTION_MOVE(手指移动)。所以点击的时候就执行ACTION_DOWN以及ACTION_UP两次的操作,但是如果你的手指移动了的话,还会进行多次ACTION_MOVE的操作。

二、正题:关于Touch事件分发机制的探索

1、Touch事件的主角们,无非就是与用户直接交互的Activity,ViewGroup以及View,Touch事件的参与方法也就是事件分发(dispatchTouchEvent),事件拦截(onInterceptTouchEvent),事件响应(onTouchEvent)。这里需要说明的是Activity中没有事件拦截,View中也没有事件拦截,可以理解成是事件拦截是ViewGroup对于自己的子View的Touch事件进行拦截,其实ViewGrop是继承View的子类,用来充当View的容器,将其中的View视作自己的孩子,对它的子View进行管理,当然它的孩子也可以是ViewGroup类型。所以可以把ViewGroup看做是一个View的集合。
这里写图片描述

2、Touch事件分发的实质:

当我们手指点击某个控件的时候,其实是分发找出ACTION_DOWN这个动作的真正实施者,找到这个动作真正的实施者后,将这次事件交给这个实施者进行消费(返回True),那么这次的动作算是完成了。

3、手指点击Button的事件分发流程:
假设我们的手指点击了一个Activity中的Button,假设这个Button在一个ViewGroup中,而这个那么用户可以直接看到的是Activity,场景如下(首先应该了解的是ViewGroup的树形结构,一个ViewGroup包含若干个View):

这里写图片描述

那么我们的手指点击了可见的某一个View,那么Touch事件的ACTION_DOWN会进行事件分发(dispatchTouchEvent),调用的顺序为:1-2-3-6-7-8–4-5,事件分发过程中遇到ViewGroup的时候,首先会判断ViewGroup的onInterceptTouchEvent是否拦截,如果不拦截,那么本次事件继续分发;dispatchTouchEvent事件的返回值为boolean,如果遍历分发的过程中返回了true,那么本次分发结束,找到了消费对象,将执行那个View的onTouchEvent事件。加入我们点击了6号的View,那么dispatchTouchEvent执行到6号的时候就会中断,7-8-4-5都不会执行到。那么需要注意的是1、2、3、6事件都执行了ACTION_DOWN的操作,而只有6号View执行了本次Touch的完整事件。假设分发过程中所有的dispatchTouchEvent都返回了false,那么本次的Touch事件就由Activity进行消费了。

三、总结:

1.ViewGrop是继承View的子类,用来充当View的容器,将其中的View视作自己的孩子,对它的子View进行管理,当然它的孩子也可以是ViewGroup类型。所以可以把ViewGroup看做是一个View的集合。

2.ViewGrop和View组成了一个树状结果,根节点为Activity。事件分发dispatchTouchEvent分发按照树形从左到右递归遍历,事件分发是分发ACTION_DOWN的动作。

3.一个完整的Touch事件由一个Action_Down、若干个Action_Move(可以没有)、一个Aciton_UP组成

4.当Acitivty接收到Touch事件时,将遍历子View进行ACTION_Down事件的分发。ViewGroup的遍历可以看成是递归的。分发的目的是为了找到真正要处理本次完整触摸事件的View,找到这个View后会在dispathTouchEvent事件中返回true结束本次ACTION_Down的分发,这个View会在onTouchEvent处理本次事件消费并返回true。

5.onInterceptTouchEvent拦截事件是ViewGroup所特有的拦截自己的子View的ACTION_DOWN事件的分发,使自己获取本次分发的消费的权利,中止本次事件分发。

6.当本次事件分发所有子View都不处理(返回false),那么久会触发Acitivity的onTouchEvent方法,有Activity做本次事件的消费。

7.默认不复写事件分发机制的方法的话,所有的返回结果都为false。如果要做本次事件分发的终结点的话,记得要把onTouchEvent的返回结果改为true,结束本次Touch事件的传递。

好了,我大概只知道这么多了~~我觉得完全可以转载别人的博客,但是我觉得应该把自己理解的融合别人的博客,把自己的想法show出来,哪怕只是抄一遍,也比ctrl+c,ctrl+v来的好。重复造轮子是难逃的宿命了,哎哎~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值