Android view触摸事件分发dispatchTouchEvent 拦截 onInterceptTouchEvent 处理 onTouchEvent

MotionEvent.ACTION_DOWN//按下事件

MotionEvent.ACTION_MOVE//移动事件

//结束事件
MotionEvent.ACTION_UP://按下直接抬
MotionEvent.ACTION_CANCEL://事件被上层节点intercept了,我收不到event了,也就cancel了

然后,再了解,android的事件是怎么传播的

不多说概念,直接上流程
一 、MotionEvent.ACTION_DOWN(按下事件)

  1. 第一步当然是处理MotionEvent.ACTION_DOWN事件,由事件所在的 活动 调用dispatchTouchEvent(MotionEvent event)准备 分发这个按下事件(如果不被onInterceptTouchEvent拦截)事件会分发到view树结构至事件发生的最小view节点的方法中,这一相关的view节点树结构,我在此文章称之为 事件分发view节点树
  2. 事件分发到ViewGroup类型的节点时,节点会接收到Activity发来的按下事件会 依序 分发到自身的2个方法 中,方法如下所示
    1. public boolean dispatchTouchEvent(MotionEvent event)//此方法默认返回super.dispatchTouchEvent(event)
    2. public boolean onInterceptTouchEvent(MotionEvent ev)//如果在此方法中返回true就代表拦截事件分发,也就意味事件分发在此类型为viewGroup的view节点中断,不会继续沿着事件分发view节点树向下分发此事件。
  3. 如果一切顺利没人拦截事件分发到最小View节点时,节点会调用最小节点的如下所示方法
    1. dispatchTouchEvent(MotionEvent event)
  4. 如果事件分发view节点树没被拦截,那就是由最小view节点中的public boolean onTouchEvent(MotionEvent event)作为起始节点沿着 事件分发view节点树向上分发,但是如果被拦截了,就由拦截的viewGroup节点public boolean onTouchEvent(MotionEvent event)作为起始节点, 准备 把此按下事件向上分发事件分发view节点树 上的每个节点的public boolean onTouchEvent(MotionEvent event)中,直到分发到根节点也就是Activity的public boolean onTouchEvent(MotionEvent event)方法中为止。
    但是只要有任意一个节点在自身的public boolean onTouchEvent(MotionEvent event)方法中返回true,那么事件向上分发就会在此节点中断,也就意味着事件在事件分发view节点树上就只向上分发到此节点的public boolean onTouchEvent(MotionEvent event)方法中为止,不会继续向上级节点分发这此事件。MotionEvent.ACTION_DOWN(用户按下)事件分发就此结束。

二、MotionEvent.ACTION_MOVE(移动事件)
第一步当然还是activity的事件分发dispatchTouchEvent(MotionEvent event),当然这次分发的是移动事件,不是按下事件,如果在MotionEvent.ACTION_DOWN(用户按下)按下事件分发流程完毕后,事件分发view节点树上没有任何一个节点在自身的public boolean onTouchEvent(MotionEvent event)方法返回true的话,就意味着没有view节点处理,那么Activity只会把事件分发给自身的public boolean onTouchEvent(MotionEvent event),反之,如果有某个节点在MotionEvent.ACTION_DOWN(用户按下)事件分发流程中在自身的public boolean onTouchEvent(MotionEvent event)返回true的话就意味着这移动事件在这个view节点中要被处理,用专业的词就就是移动事件要在此节点中被消费。所以activiy会把此移动事件根据事件分发view节点树分发至此返回true的节点为止,分发到此移动事件的viewGroup类型节点都会把这个移动事件依序发发到自身的 2 个方法中,方法如下所示。

  1. public boolean dispatchTouchEvent(MotionEvent event)
  2. public boolean onInterceptTouchEvent(MotionEvent event)//可以用此方法拦截移动事件,拦截之后,Activity重新分发移动事件直到此view节点的onTouchEvent为止。
    但如果分发到事件的节点是view类型的节点(不太确定,想拦截事件直接在oninter返回true就行了)或者是在onInterceptTouchEvent返回ture的节点的上级节点,那么就只会调用以下所示方法(dispaev),通俗的说就是事件以被此节点拦截了,事件只会分发到此节点的上级包括自身的dispatchTouchEvent方法,不会调用节点onInterceptEvent方法,最后发送到自身节点的onTouchEvent方法为止,无论返回什么值都不会继续传到上级节点的ontouchevent。为什么呢?一个事件被拦截了,就代表此由此节点处理接下来的手势了,上级节点以及下级节点都能不处理了,如果下个move事件再次分发经过此上级节点事件如果能分发到onInterceptTouchevent或下级节点收到分发事件还有上级的ontouchevent,就会使当前想处理手势的节点无法正常接收move事件进行手势处理。
    public boolean dispatchTouchEvent(MotionEvent event)
    事件最后会分发给返回true的节点,此节点会调用自身的两个方法如下所示,最后由节点的public boolean onTouchEvent(MotionEvent event)方法收到此移动事件后被调用后,此MotionEvent.ACTION_MOVE(移动事件)分发结束。不会继续向上级节点的ontouchevent分发事件。
    分发结束后,我就可以在返回true的节点中的onTouchEvent方法,或 dispatchTouchEvent方法中进行触摸的业逻辑开发。
  3. public boolean dispatchTouchEvent(MotionEvent event)
  4. public boolean onTouchEvent(MotionEvent event)

三、MotionEvent.ACTION_UP、MotionEvent.ACTION_CANCEL(结束事件)
结束事件的分发同 移动事件分发一样,在按下事件中onTouchEvent返回true的 节点中的onTouchEvent中为止。结束事件分发与移动事件分发同理

原理图示如下
在这里插入图片描述

再说明一个知识点
当一个view层级不够,被一个遮挡view遮挡住自身view时,如果这个遮挡view的在ontouchEvent MotionEvetnt.Action_Donwn中返回true。这个被遮挡的view就收不到Acton_move事件。因为遮挡view在接收onTouchEvent ACTION_DOWN事件要比被遮挡view先收到。(放弃坑太深了,action_move也不能放回true )
如图所示
在这里插入图片描述

参考文章
事件分发

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值