View的事件分发机制

View的事件分发机制

View的事件分发机制主要分为三点

,第一点是Activity将点击事件分发给ViewGroup

第二点是ViewGroup将事件自己处理或者分发给子View

第三点便是子View自行处理,或者子View处理不了转交给ViewGroup

现在依次来看

Activity对点击事件的分发过程

Activity的dispatchTouchEvent主要是Activity内部的Window来完成,Window将判断

getWindow().superDispatchTouchEvent(ev)

是否为false,如果为false,则由Activity自己处理这个点击事件,即Activity调用onTouchEvent,而如果返回值为true,表示Window已经消费了该点击事件,不再继续向下传递,由PhoneWindow(PhoneWindow是Activity的实现类)处理后续的操作。

PhoneWindow将事件传递给DecorView,最后又通过DecorView传递给ViewGroup

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bPojoUAk-1684655693454)(../../assets/流程图-导出 (1)].png)

ViewGroup对事件的分发过程

ViewGroup对事件的分发过程有3种可能性,一种是ViewGroup自己拦截的点击事件,然后自己处理了,还有一种是ViewGroup没有拦截事件,但是传递给了子View,但是子view没办法自己处理,最后又交给了ViewGroup处理。最后一种是ViewGroup没有拦截事件,传给子View,子View处理了

ViewGroup拦截事件

ViewGroup如果onInterceptEvent返回了true,则表示该事件被ViewGroup拦截住了,先判断有没有onTouchListener,如果有这个则调用里面的onTouch,没有则判断有没有onTouchEvent,如果里面设置了onClickListener则调用这个方法。

如果返回的是false,则传递给子View

但是onInterceptEvent并不是每次都会调用。

它有一个FLAG_DISALLOWINTERCEPT标记,这个标记会进行判断:

1.如果是一个ACTION_DOWN行为的话,它会在onterceptTouchEvent()里面进行判断是否进行拦截,如果不进行拦截的话且如果子View消费了该事件,则FLAG_DISALLOWINTERCEPT标记对于同一个事件的ACTION_MOVE,ACTION_UP等等都不再进行拦截了。

2.如果不进行拦截的话,且子View没有消耗该事件,ViewGroup仍然有可能拦截同一个事件序列内的其他动作。

3.如果进行拦截了当前事件,并不会将该事件传递给子View进行处理。这意味着同一个事件序列内的其他动作**(如ACTION_MOVE、ACTION_UP等)**会被该ViewGroup拦截。

所以ViewGroup的onInterceptEvent并不会一直调用

我们再看看ViewGroup把事件传递给子View吧

ViewGroup的传递

ViewGroup会对所有的子View进行一次遍历,并且对它们进行判断,

对于子View有以下几种判断:

1.如果子View的位置不在点击事件的坐标范围内或者子View不接收指针事件(如设置了不可点击或不可触摸),则跳过该子View。
2.如果子View已经在处理点击事件,即已经接收到ACTION_DOWN事件并在处理中,直接将触摸事件传递给该子View,并将点击事件标记为已经分发给子View处理。
3.如果子View还未处理点击事件,则调用dispatchTouchEvent()方法将点击事件传递给子View进行处理。
4.如果所有的子View都无法处理点击事件,或者ViewGroup没有子View,则ViewGroup会自己处理该点击事件。
总结起来,顶级View对点击事件的分发过程包括拦截判断、子View的遍历和分发。如果ViewGroup拦截了ACTION_DOWN事件,它会处理该事件;如果没有拦截,它会将事件传递给合适的子View进行处理,如果没有合适的子View,则自己处理该事件

View对点击事件的处理

这里的View不包含ViewGroup,因为ViewGroup的我们刚才已经讲过了

View没办法继续向下传递了,所以它就两种情况:

1.自己可以处理,然后把这个事件消耗了

2.自己没办法处理,然后转交给ViewGroup处理

就直接说View自己处理的

首先,View会判断是否存在onTouchEvent()OnTouchListenerOnClickListener等相关事件处理方法或监听器。
如果存在OnTouchListener,则会调用OnTouchListeneronTouch()方法,如果onTouch()方法返回true,表示该触摸事件已被消费,不再继续传递给其他处理方法或监听器。
如果存在OnClickListener,并且点击事件满足点击条件(如点击类型、点击位置等),则会调用OnClickListeneronClick()方法,并且事件被视为已经消费。
如果点击事件还未被消费,则会判断View的clickable和longClickable属性是否为true如果clickable为true,则视为该View可以接收点击事件并消费;如果longClickable为true,则视为该View可以接收长按事件并消费。
如果上述条件均不满足,或者View已经消费了点击事件,则事件会继续向上层父View传递,由父View或上层ViewGroup处理。
,则视为该View可以接收长按事件并消费。
如果上述条件均不满足,或者View已经消费了点击事件,则事件会继续向上层父View传递,由父View或上层ViewGroup处理。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值