android 个人对事件传递的总结

来源:互联网 发布:淳化阁帖 知乎 编辑:程序博客网 时间:2024/05/18 03:22

关键的三个方法

  • dispatchTouchEvent:事件的分发工作,返回值代表事件是否被消耗
  • onInterceptTouchEvent:ViewGroup用于拦截事件的方法
  • onTouchEvent:事件处理的方法

阅读前的关键字说明

  • 后续事件:即down事件后的move跟up事件。
  • touch处理:即是先调用setOnTouchListener的listener,如果返回了false,则代表事件没有被消耗,会继续调用onTouchEvent进行处理。两个方法的返回值都代表事件是否被消耗的意思,一但消费了,事件不会继续传递

通俗的讲事件传递的思路
最顶层控件会轮流传给子控件询问是否消耗了事件,当某个子控件消耗了事件,则后续的事件(move、up)会继续传递给该控件处理。当然,传递过程中还是会继续经过父控件再到当前控件,也会继续调用父控件的onInterceptTouchEvent来询问父控件本身要不要拦截。(但不会传递给别的子控件)

事件传递的代码
是写在super.dispatchTouchEvent方法中,所以一般不能删掉这行代码

怎样确定事件被消耗
事件是否被消耗的真正代表方法是dispatchTouchEvent的返回值,返回true代表被消耗,返回false代表没被消耗。

事件传递的逻辑
事件传递的方法是dispatchTouchEvent,其实他的主要作用是询问子控件是否需要消耗掉事件,如果子控件是ViewGroup,则又会去调用他的子控件的dispatchTouchEvent来询问,而这询问是有一个规律的,就成了一个事件传递的过程。最外层是Activity来调用顶层ViewGroup的dispatchTouchEvent,然后ViewGroup也会去调用子控件的dispatchTouchEvent。方法的返回结果代表事件是否被消耗。该方法ViewGroup跟View都有,且处理方式不同。

  • ViewGroup:会先询问自己是否需要拦截事件。
    • 如果需要,则该ViewGroup不会再传递给自己的子控件,而是调用自己的touch来处理。(可能想像为该ViewGroup已经变成了一个View)
      • 如果touch返回了true,则正常,说明事件在自己这里被消费了,dispatchTouchEvent也会返回true来告诉当前ViewGroupr的父控件不用再往别的控件中传递,事件说明被自身拦截,后续事件也会继续传递到此处。
      • 如果touch返回了false,则dispatchTouchEvent也会返回false,来告诉自己的父控件事件没有被消耗,而父控件会接着传递给另一个子控件进行处理
    • 如果不需要,则会调用子控件的dispatchTouchEvent
  • VIew:会直接进行touch处理,然后touch处理的返回值就是自身dispatchTouchEvent的返回值

事件丢失
当在down事件的时候,传递到的控件当中没有一个dispatchTouchEvent返回true,则事件会丢失,之后的move及up事件,代码都不会响应,需要重新触发down事件(重新按下)

有关ViewGroup的拦截事件
拦截事件就是指让自己来touch处理,其实可以更加明了的讲,就是ViewGroup拦截事件后,就变成了一个View一样。

父控件中有两个子控件的注意事项
假设父控件有两子控件A、B,首先问了A,A控件dispatchTouchEvent返回false,代表A没有消耗事件,然后就会传递给B,而B如果消耗了的话,后续的事件就是直接先传递给父控件,再传给B,而不会再经过A。

请求ViewGroup不要拦截事件:ViewGroup有个方法叫做requestDisallowInterceptTouchEvent(boolean b)来使自身不要拦截事件,设置true则表示不要拦截,设置false则恢复正常。下面有具体的应用场景

各控件的事件传递思路与控件间的事件处理

  • Button:Button默认是会把事件消耗掉的(onTouchEvent返回true,之后dispatchTouchEvent也会返回true)
  • ListView内有一个Button:ListView是一个ViewGroup,他拦截事件的前提是在down后,进行了一定数值的上移或下移时,就会将事件抢过来自己处理(上拉下拉的效果就是处理的结果)而如果ListView的item内有一个Button,事件传递的思路是这样的:首先按下Button的时候,事件是给Button抢了过来,之后的后续事件如果是上移或下移了,事件会突然被ListVIew抢走(因为后续事件会经过ListView,且会询问ListView是否拦截,而ListView是在onInterceptTouchEvent中获取到事件的相关信息来判断是否上移下移来决定拦不拦截)
  • ScrollView内有一个ListView(假设ListVIew只占了ScrollView的一部份位置):首先事件肯定是先给了ScrollView,然后ScrollView内部再传递给ListView,而ScrollView跟ListView的拦截事件的判断都是一样的(判断是否进行了上拉或下拉,是则进行拦截)所以在进行上下滚动后,ListView是绝对拿不到事件的,但down事件是肯定会拿到。所以解决方法是在ListView中的onInterceptTouchEvent当中的down事件发生的时候,调用 ScrollView对象. requestDisallowInterceptTouchEvent(true),来让ScrollView不要抢事件,之后在up事件时,再调用 ScrollView对象. requestDisallowInterceptTouchEvent(false) 来让ScrollView恢复正常。这样做的话,就是表明当按下的地方是ListView时,上下滑动时是ListView滑动,按下时是在ScrollView内的其他地方,则是ScrollView的上下滑动。
0 0
原创粉丝点击