事件传递机制

Posted wangweizu99

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了事件传递机制相关的知识,希望对你有一定的参考价值。

事件传递机制

1.基础认知

1.1事件分发的对象:点击事件(Touch事件)(什么是事件?)

  • 定义:当用户触摸屏幕时,产生的点击事件(Touch事件)

  • 事件的类型:

    MotionEvent.ACTION_DOWN				按下View(事件的开始)
    MotionEvent.ACTION_UP				抬起View(与DOWN对应)
    MotionEvent.ACTION_MOVE				滑动View
    //MotionEvent.AVTION_CANCEL 			结束事件(非人为结束)
    
  • 一组事件的产生(图):

1.2事件传递的本质(事件传递是什么?)

当一个点击事件(MotionEvent)产生之后,系统把这一个事件传递给一个具体的View去处理的过程

先执行onTouch(),在执行onClick()

1.3事件传递的顺序

事件一般在 Activity 、 ViewGroup 、 View之间传递。

顺序:Activity -> ViewGroup -> View

1.4事件传递过程中的方法

  • dispatchTouchEvent() 传递点击事件 当点击事件能够传递给当前View时,该方法调用
  • onTouchEvent() 处理点击事件 在dispatchTouchEvent()内部调用
  • onInterceptTouchEvent() 判断是否拦截了某个事件 在ViewGroup的dispatchTouchEvent()内部调用

1.5总结

2.先看总体(事件是怎么传递的?)

整个事件传递的过程就相当于一个递归的过程:

针对一个事件(ACTION_DOWN)的传递过程:

  • dispatchTouchEvent()和onTouchEvent():
    • return true 终结事件的传递
    • return false 事件回传到父控件的onTouchEvent()处理:区别dispatchTouchEvent()事件停止向子View传递,onTouchEvent()不消费事件(无法处理事件)
    • return super.xxxx() 事件继续传递完成递归过程,ViewGroup的dispatchTouchEvent()调用时会默认执行 onInterceptTouchEvent()
  • onInterceptTouchEvent():
    • return true 拦截事件并交给自己的onTouchEvent()处理
    • return false或super 不拦截事件,并将事件传递给子View

3.详细解每个过程

4.总结

当一个控件接受一组传递的开始事件(ACTION_DOWN)并进行处理后:

  • dispatchTouchEvent() return true 那么事件就会停止传递

  • onTouchEvent() return true 剩余的事件(ACTION_UP、ACTION_MOVE)会直接传递到该控件的onTouchEvent()处理结束传递

  • 一组触摸事件分为按下、移动、抬起,称之为一个事件序列,其中移动事件会有多个。当一个View决定自己消费一组事件需要在按下时就给出结果,反之如果在按下时决定消费意味着这一组事件序列均由自己消费。

4.1两个实验

  1. 在View的dispatchTouchEvent()返回false 并在ViewGroup的onTouchEvent()返回true

    红色代表DOWN 蓝色代表 MOVE和UP

  2. 在ViewGroup的onTouchEvent()返回true

    红色代表DOWN 蓝色代表 MOVE和UP

4.2 onTouch()和onTouchEvent()的区别

两个方法都在dispatchTouchEvent()中调用,onTouch()优先级较高

若果onTouch()中返回true则onTouchEvent()不在执行

onTouch能够执行的前提:

  1. mOnTouchListener不为空
  2. 点前点击的控件必须是ENABLED??

5.常见问题及解决(事件传递过程中会遇到什么?)

5.1常见的滑动冲突

  1. 滑动方向不一致
  2. 滑动方向一致
  3. 多层滑动嵌套

5.2滑动冲突的解决方法

  • 外部拦截法

    外部拦截法,就是所有事件都先经过父容器的拦截处理,由父容器来决定是否拦截。这种方式需要重写父容器的onInterceptTouchEvent()方法

    1. 不拦截ACTION_DOWN事件
    2. ACTION_MOVE事件根据需求判断是否拦截
    3. ACTION_UP必须放回false
  • 内部拦截法

    内部拦截法是指父容器不拦截任何事件,所有事件都传递给子元素。内部拦截法需要配合requestDisallowInterceptTouchEvent()方法才能正常工作。这种方式需要重写子元素的dispatchTouchEvent()方法

6.借鉴

图来自:https://juejin.cn/post/6844903472395976711

内容总结自:https://juejin.cn/post/6844903472395976711

https://jsonchao.github.io/

http://blog.csdn.net/guolin_blog/article/details/9097463

7.疑问

  • 每次解决冲突都要重写布局?
  • 两个主fragment不存在嵌套,是否改为一个Activity嵌套一个Fragment在嵌套一个Fragment?
    guolin_blog/article/details/9097463

7.疑问

  • 每次解决冲突都要重写布局?
  • 两个主fragment不存在嵌套,是否改为一个Activity嵌套一个Fragment在嵌套一个Fragment?

以上是关于事件传递机制的主要内容,如果未能解决你的问题,请参考以下文章

Android 事件传递机制

Android Touch事件传递机制全面解析(从WMS到View树)

Android 事件分发事件分发源码分析 ( ViewGroup 事件传递机制 四 | View 事件传递机制 )

事件传递和响应机制

Android 事件传递机制进阶

Android事件传递机制