欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

事件分发传递过程

程序员文章站 2022-04-14 11:21:01
一 是什么,怎么用,为什么事件分发传递过程,点击/触摸在Activity和控件之间,控件和控件之间的传递过程,明白点击事件由哪个对象发出,经过哪些对象,最终到达哪个对象并最终得到处理。了解并熟悉有助于分析各种滑动失效问题为什么要有事件分发传递Android的view是树形结构的,view可能会重叠在一起,当我们点击/触摸的时候,这个事件该给谁所以制定一个机制,先保证这个事件能传递到每一个view去,然后哪个view想消费这个事件,就拦截这个事件,消费掉它二 学习之前应该了解事件分发的三个方法...

一 是什么,怎么用,为什么

事件分发传递过程,点击/触摸在Activity和控件之间,控件和控件之间的传递过程,明白点击事件由哪个对象发出,经过哪些对象,最终到达哪个对象并最终得到处理。了解并熟悉有助于分析各种滑动失效问题

为什么要有事件分发传递

Android的view是树形结构的,view可能会重叠在一起,当我们点击/触摸的时候,这个事件该给谁

所以制定一个机制,先保证这个事件能传递到每一个view去,然后哪个view想消费这个事件,就拦截这个事件,消费掉它

二 学习之前应该了解

事件分发的三个方法

  • dispatchTouchEvent 事件分发
  • onInterceptTouchEvent 阻拦机制
  • onTouchEvent 消费机制
  • requestDisallowInterceptTouchEvent 子类请求父类解除限制

MotionEvent

  • ACTION_DOWN

  • ACTION_MOVE

  • ACTION_UP

  • ACTION_CANCEL

三 过程

我们可以简化成一个3层的流程图来解释和说明
从上往下依次是Activity、ViewGroup、View
##ACTION_DOWN

  • 事件由activity的dispatchTouchEvent做分发
    传递方向向下:dispatchTouchEvent和onTouchEvent返回true就不会向下传递了;
    传递方向向上:onTouchEvent返回false才会向上传递,返回true不会传了

Android事件分发是先传递到ViewGroup,ViewGroup传递到View。
如果在ViewGroup中通过onInterceptTouchEvent对事件传递进行拦截,返回true,即不允许事件向子View传递,然后调用本身的onTouchEvent事件,进行处理,此时onTouchEvent也具有true和false,True代表事件已经被view所消化;false会往上传递,一直到activity中;
onInterceptTouchEvent返回false代表不拦截事件,即允许事件继续向子view传递,子view如果将传递到事件消费掉,ViewGroup中将无法接收到任何事件

事件的响应顺序

onTouch和onClick事件同时发生
onTouch的执行先于onClick的执行

优先级:OnTouchListener > onTouchEvent > OnClickListener

onTouch以及onTouchEvent的区别

这两个方法都是在View的dispatchTouchEvent中调用的,onTouch优先于onTouchEvent执行,如果在onTouch方法中通过返回true将事件消费掉,onTouchEvent将不会再执行

onTouch能够执行的前提是mOnTouchListener的值不能为空,点击的控件必须是enable的,mOnTouchListener.onTouch返回为true

Button点击的调用过程

Button/dispatchTouchEvent—TextView—View/dispatchTouchEvent

ViewGroup点击调用过程

点击ViewGroup时候,会先去寻找ViewGroup下面的所有子view,直到找到当前点击的区域View,调用child.dipatchTouchEvent

注意

如果执行ACTION_DOWN的时候返回了false,后面ACTION_MOVE,ACTION_UP就不会得到执行了,简单来说就是当dispatchTouchEvent在进行事件分发的时候,只有前一个action返回true,才会触发后一个action?

题目

  • 为什么我们在onTouchEvent中返回ture不会执行onclick事件呢
    OnClickListener.onClick()是在原生的View.onTouchEvent()方法里面回调的, 你自己重写了这个方法, 而且不调用super.onTouchEvent(event)的话当然就不会回调onClick()方法了
  • 如果子控件被限制住了,应该如何进行使他的操作没有被限制?
    根据上面源码我们可以,重写onTouchEvent ,使父控件不会限制住
    getParent().requestDisallowInterceptTouchEvent(true);

参考学习博客:

https://blog.csdn.net/weixin_39460667/article/details/82991688
https://blog.csdn.net/lijiuche/article/details/70807672//demo研究事件传递
https://www.jianshu.com/p/303d0e6f3f69
https://www.cnblogs.com/aademeng/articles/10702653.html//滑动冲突解决

Activity dispatchTouchEvent事件分发的源头

WMS获取Touch事件

—>ViewRootImpl.deliverInputEvent

—>ViewRootImpl$InputStage(即ViewPostImeInputStage).deliver【这个过程不同Android版本不一样】

—>ViewRootImpl$ViewPostImeInputStage.onProcess

—>ViewRootImpl$ViewPostImeInputStage.processPointerEvent【这一步可以根据InputDevice.SOURCE_CLASS_POINTER这个常量来找】

—>mView.dispatchPointerEvent(event);【这里的mView就是DecorView】

—>Activity.dispatchTouchEvent

【Activity.dispatchTouchEvent是来自Window.Callback.dispatchTouchEvent,Activity.dispatchTouchEvent调用的位置是在PhoneWindow.DecorView. dispatchTouchEvent,此处指的是DecorView它本身重写的那个,而不是super的,注意两者的区别】

接下来就根据艺术探索里的去看吧
以上分析源于API23源码

https://blog.csdn.net/conan9715/article/details/78529055

本文地址:https://blog.csdn.net/weixin_42547039/article/details/108988016