Pich Blog

关注移动开发,大数据,云计算,软件架构!

9.View的事件分发

概述

事件分发可以说是一个难点,而且经常还会用到,因为不管是你用系统控件还是自定义控件都会遇到事件冲突。

事件分发相关方法

ViewGroup

dispatchTouchEvent

用来进行事件分发,如果当前View能够接收到事件,那么该方法一定调用。返回值受当前View的onTouchEvent和下级View的dispatchTouchEvent方法,表示是否消耗该事件,如果消耗了那么他的父类不会再调用onTouchEvent。

onInterceptTouchEvent

该方法在dispatchTouchEvent方法中调用,用来判断当前控件是否拦截某个事件,如果当前View拦截了,那么同一个事件序列中,不再调用该方法,如果拦截了会调用当前View的onTouchEvent。如果没有拦截,那么在dispatchTouchEvent方法中事件会传递给子View。

onTouchEvent

该方法在dispatchTouchEvent方法中调用,返回结果表示是否消耗当前时间,如果不消耗,同一个事件序列中,不再调用该方法。

View

dispatchTouchEvent

onTouchEvent

可以用如下伪代码表示:

当然这只是伪代码,真实情况肯定更复杂,但是大体流程是这样。

总结:

事件传递规则:对于一个ViewGroup,事件会传递给他的dispatchTouchEvent方法,如果该ViewGroup的onInterceptTouchEvent返回true,也就是说拦截了事件,那么该ViewGroup的onTouchEvent方法就会被调用,如果返回false,表示不拦截,那么就会调用子View的dispatchTouchEvent方法,继续事件分发。

设置了OnTouchListener

当一个View设置了OnTouchListener,那他的onTouchEvent又该如何执行了?

如果设置了,他的OnTouchListener里面的onTouch会先执行,如果返回false,当前view的onTouchEvent才会调用,如果返回true,onTouchEvent就不会调用,也就是说可以通过OnTouchListener将onTouchEvent替换掉。如果设置了OnClickListener,那么只有当onTouch返回false时,可能调用。

事件分发路线

事件分发路线也就是说当在屏幕上按下,这个事件怎么分发的,从哪里到那里。

传递顺序:Activity-Window-View。

如果一个View的onTouchEvent返回true,那么他的父类onTouchEvent会被调用,如何还返回true,那他的父类父类的onTouchEvent被调用,依次类推。如果所有的元素都返回false,那么activity的onTouchEvent被调用。

事件传递结论

  1. 同一个事件序列从手指触摸那一刻起,到手指离开那一刻这过程中产生一系列的事件,由一个down事件开始,多个move事件,一个up事件结束。
  2. 正常情况下,一个事件只有被一个view拦截且消耗。但是的参考3,因为上面说的一旦拦截下来了,那么该事件所有序列都交给他处理。但是可以通过onTouchEvent强行将事件传递给其他View。
  3. 如果某个View一旦拦截了事件,那个这一序列的事件都只能由他处理,并且不会再调用他的onInterceptTouchEvent方法。因为你都拦截说要处理了,后面的事件肯定不需要再问了,直接交给你处理就行了。
  4. 如果某个View一旦开始处理事件,如果他不消耗ACTION_DOWN事件(onTouchEvent返回了false),那么这一序列的事件都不交给他处理了,事件将交给他的父类处理。也就是说父类的onTouchEvent被调用。
  5. 如果View不消耗ACTION_DOWN以外的事件,那么这个事件就消失了,父类的onTouchEvent不会被调用。并且当前View可以收到该序列后续事件,最终这个消失的事件会传递给Activity处理。
  6. ViewGroup默认不拦截任何事件,Android源码中ViewGroup的onInterceptTouchEvent方法默认返回false。
  7. View没有onInterceptTouchEvent方法,一旦事件传递给他,那么他的onTouchEvent方法就会被调用。
  8. View的onTouchEvent默认都会消耗事件(默认返回false),除非他是不可点击的(clickable,longClickable同时为false),View的longClickable默认为false,clickable根据控件不同,值也不同,比如:Button默认为true,TextView默认为false。
  9. View的enable属性不影响onTouchEvent方法的返回值,哪怕为disable,只要可点击,就返回true。
  10. onClick会发生的前提是当前View是可点击的,并且他收到了down和up事件。
  11. 事件传递是从外向内的,即总先传递个父元素,在由父元素分发给子元素,通过requestDisallowInterceptTouchEvent方法可以在资源上中干预父元素的事件分发,但是ACTION_DOWN事件除外。
点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注