Android总结------view事件分发

view分发事件之前:

整个事件分发从activity->window->顶级view ->子view逐层向里传递事件,顶级view接收事件后按照相应的分发机制分发事件,期间如果一个view的onTouchEvent返回false表示他不处理这个事件,那么就会调用父容器的onTouchEvent()来处理这个事件,如果所有view都不处理,那么将返回给activity调用onTouchEvent处理。

过程简单来说就是受到事件后一层一层向内(子view)分发,默认不拦截。分发到最顶层view后开始处理,如果不处理则一层一层向外(父view)回传这个事件,直到将此事件消耗。若无人消耗则最中调用activity的处理方法。

view分发事件中:

viewGroup主要围绕三个方法进行:

dispatchTouchEvent()

onInterceptTouchEvent()

onTouchEvent()

viewGroup的dispatchTouchEvent方法比较复杂,其中首先判断是否拦截这个事件的流程:

当viewGroup不拦截事件的时候,将事件分发给他的子view判断是否拦截(默认不拦截),直到最后一层子view开始处理,子view若不处理,会逐层返回上层处理:

遍历viewGroup中所有的子view,逐个判断其是否可以接受点击事件,主要通过两点进行衡量:

  1. 子元素是否在播动画

  2. 点击事件坐标是否在子元素区域内

满足以上这两个条件则会交由这个view处理事件,调用dispatchTransformedTouchEvent(),该方法内当参数child不为空时,调用子view的dispatchTouchEvent处理事件,当参数child为空时则调用父view的dispatchTouchEvent来处理事件。

当找到符合条件处理的view之后,通过addTouchTarget方法给mFirstTouchTarget赋值并跳出循环(mFirstTouchTarget是单列表结构???)。根据上图可知mFirstTouchTarget是否为空直接影响整个viewGroup对事件拦截的策略。

如果遍历到最后事件都没有被合理的处理,包含两种情况,一是没有或没有合适的子view,二是子view处理了但是在dispatchTouchEvent中返回了false,一般是子view在onTouchEvent中返回了false,viewGruop就会自己处理点击事件(调用dispatchTransformedTouchEvent()方法,参数child为null,即调用super.dispatchTouchEvent()处理事件)

在view的dispatchTouchEvent中:

view(不包括viewGroup)中不含子view,所以事件只能是自己处理,不处理则返回上级处理。

主要流程为:

只要view的CLIKCKABLE和LONG_CLICKABLE有一个为true,那么这个view就会消耗这个事件,即onTouchEvent方法返回true,不管是否是DISABLE状态。

当ACTION_UP事件发生时会调用performClick方法,如果View设置了onClickListener,那么performClick内部会调用onClick方法。

所以优先级排序为:onTouchListener>onTouchEvent>onClickListener

一些结论:

  1. 正常情况下,一个事件序列只能被一个view拦截并消耗,view一旦开始拦截,那么整个事件序列只能都由他处理(在能够传递给他的前提下),因此就不会再调用这个view 的onInterceptEvent()调用方法来询问是否需要拦截他

  2. 某个view一旦开始处理事件,如果不消耗ACTION_DOWN事件(onTouchEvent返回了false),那么同一个事件序列中的其他事件都不会交由他处理了,这些事件将重新交给他的父view来处理(调用其onTouchEvent)。

  3. 如果view拦截不消耗除了ACTION_DOW以外的事件,那么这整个点击事件将会消失(父view的onTouchEvent也不会被调用)。当前view可收到后续事件,但最终这些事件将交由Activity处理。

  4. view(只是view,不是viewGroup)没有onInterceptEvent方法,一旦有点击事件传给他,他的onTouchEvent就会被调用。

建议参考链接:Android中的dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()_xyz_lmn的博客-CSDN博客_android dispatchtouchevent

解决滑动冲突:

  1. 外部拦截法

重写父view的onIntercepterTouchEvent

当事件是ACTION_MOVE时进行判断,如果是父view需要的点击事件则intercepted = true,其他情况和事件均为false

  1. 内部拦截法

重写子view的dispatchTouchEvent和父view的onIntercepterTouchEvent

dispatchTouchEvent:ACTION_DOWN时调用requestDisallowInterceptTouchEvent(false),ACTION_MOVE时如果是父容器需要的事件则调用requestDisallowInterceptTouchEvent(true),最后return super.dispatchTouchEvent

onIntercepterTouchEvent:ACTION_DOWN时不拦截,其他全拦截

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值