Jump to content
  • Hello visitors, welcome to the Hacker World Forum!

    Red Team 1949  (formerly CHT Attack and Defense Team) In this rapidly changing Internet era, we maintain our original intention and create the best community to jointly exchange network technologies. You can obtain hacker attack and defense skills and knowledge in the forum, or you can join our Telegram communication group to discuss and communicate in real time. All kinds of advertisements are prohibited in the forum. Please register as a registered user to check our usage and privacy policy. Thank you for your cooperation.

    TheHackerWorld Official

Recommended Posts

Android事件分发机制

为什么会有事件分发机制

android上面的view是树形结构的,view可能会重叠在一起,当我们点击的地方有过个view都可以响应的时候,这个点击事件应该交给谁来处理,就需要事件分发机制。

1.概述

事件分发的三个重要方法

public boolean dispatchTouchEvent(MotionEvent event)
public boolean onInterceptTouchEvent(MotionEvent event)
public boolean onTouchEvent(MotionEvent event)

MotionEvent取值如下:

    public static final int ACTION_DOWN             = 0;
    public static final int ACTION_UP               = 1;
    public static final int ACTION_MOVE             = 2;
    public static final int ACTION_CANCEL           = 3;

ACTION_DOWN 表示手指按下时发出的消息
ACTION_UP 表示手指抬起时发出的消息
ACTION_MOVE 表示手指移动时发出的消息
ACTION_CANCEL 表示结束事件时手指发出的消息

举个例子讲解事件分发机制:

布局为Activity嵌套两个ViewGroup,最顶层的ViewGroup里面套一个TextView

如下不拦截消息时,ACTION_DOWN消息的完整传递过程为:

image

注意:
对于Activity来说不需要 onInterceptTouchEvent 方法,因为拦截没有意义,拦截后整个view树都点击不了。
对于view来说,事件要么消费,要么回传,也没有拦截的必要。

因此在Activity,ViewGroup,TextView中都有disPatchTouchEvent方法和onTouchEvent方法。
对于ViewGroup来说,多了一个onInterceptTouchEvent方法。

先说不包含 onInterceptTouchEvent 方法时消息传递过程,再来看包含onInterceptTouchEvent方法时消息传递过程

2. 不包含 onInterceptTouchEvent 方法时 ACTION_DOWN 消息传递过程

什么是拦截?看下面这三个方法都有一个boolean类型的返回值。默认返回false表示没有拦截,即自己不做处理。返回true时,表示自己处理这个事件,就是拦截了。

public boolean dispatchTouchEvent(MotionEvent event)
public boolean onInterceptTouchEvent(MotionEvent event)
public boolean onTouchEvent(MotionEvent event)

2.1 dispatchTouchEvent 返回值简介

dispatchTouchEvent 方法对于返回值的处理比较特殊,默认的处理方法并不是返回false,而是直接调用super.dispatchTouchEvent.这种处理方式与直接返回false不同。因此对于dispatchTouchEvent,有三种返回值:

  • 默认的super.dispatchTouchEvent
  • 返回true
  • 返回false

2.2 在 dispatchTouchEvent 方法中返回 true 拦截消息

2.2.1 在 Activity 的 dispatchTouchEvent 方法中拦截消息

在 Activity 的 dispatchTouchEvent 方法中拦截消息后,消息会直接断掉,不会往任何地方传递,只有 Activity 的 dispatchTouchEvent 方法收到 ACTION_DOWN 消息。

2.2.2 在 ViewGroup 的 dispatchTouchEvent 方法中拦截消息

在 ViewGroup 的 dispatchTouchEvent 方法中拦截消息后,ACTION_DOWN 消息同样会直接停止传递,其他任何子控件都收不到消息。

2.2.2 在 View 的 dispatchTouchEvent 方法中拦截消息

在传递到 View 的 dispatchTouchEvent 方法后,消息就停止传递了。

因此,无论在哪个控件的 dispatchTouchEvent 方法中拦截消息,消息都会直接停止传递,后面的子控件都不会接收到这个消息。

2.3 在 dispatchTouchEvent 方法中返回 false 拦截消息

先说结论:在 dispatchTouchEvent 方法中返回 false 拦截消息后,消息不会直接停止传递,而是向父控件的 onTouchEvent 方法回传。

2.3.1 在 View 的 dispatchTouchEvent 方法中返回 false

2.3.2 在 ViewGroup2 的 dispatchTouchEvent 方法中返回 false

2.3.3 在 ViewGroup1 的 dispatchTouchEvent 方法中返回 false

2.3.4 在 Activity 的 dispatchTouchEvent 方法中返回 false

从上面这些消息传递过程中可以看出,在控件的 dispatchTouchEvent 方法中返回 false 后, ACTION_DOWN 消息会在 dispatchTouchEvent 这条线上停止传递,并向其父控件的 onTouchEvent 方法回传。

2.4 在 onTouchEvent 方法中拦截 ACTION_DOWN 消息

onTouchEvent 方法中,默认返回 false,表示不拦截; 当返回 true 时, 表示拦截。

先说结论:
无论哪个控件的 onTouchEvent 方法拦截 ACTION_DOWN 消息, 消息都会直接停止传递, 后面的父控件都不会接收到这个消息。

总结:

  • dispatchTouchEvent 和 onTouchEvent 方法一旦返回true拦截消息, ACTION_DOWN 消息就会停止传递,正常流程下的后续节点都不会收到 ACTION_DOWN 消息了。
  • 当 dispatchTouchEvent 方法,返回 false 时,首先会拦截 ACTION_DOWN 消息,消息不会继续传给子控件,而是传给父控件的 onTouchEvent,然后继续回传。

3. 在 onInterceptTouchEvent 方法中的 ACTION_DOWN 消息传递流程

3.1 onInterceptTouchEvent 方法的作用

首先,只有 ViewGroup 具有 onInterceptTouchEvent 方法, Activity 和 View 中都没有这个方法。

然后, onInterceptTouchEvent 方法其实就是一个拦截过滤器。每个 ViewGroup 每次在处理消息分发时,都会问一问拦截器要不要拦截(也就是这个消息要不要自己处理)。要处理就返回true,然后交给自己的 onTouchEvent 方法处理。如果不拦截,就继续往子控件传递。默认是不拦截的。

3.2 在 ViewGroup 的 onInterceptTouchEvent 方法中拦截 ACTION_DOWN 消息

3.2.1 仅在 ViewGroup2 的 onInterceptTouchEvent 方法中拦截 ACTION_DOWN 消息

3.2.2 仅在 ViewGroup1 的 onInterceptTouchEvent 方法中拦截 ACTION_DOWN 消息

3.2.3 在 ViewGroup2 的 onInterceptTouchEvent 和 onTouchEvent 方法中拦截 ACTION_DOWN 消息

总结:

在 ViewGroup 的 onInterceptTouchEvent 方法中拦截 ACTION_DOWN 消息,会改变 ACTION_DOWN 消息的流向,让它直接流向当前 ViewGroup 的 onTouchEvent 方法。
同样,如果 onTouchEvent 方法没有拦截继续拦截消息,则消息会继续传递。如果某个 onTouchEvent 方法中拦截消息的话, ACTION_DOWN 会直接停止传递。

4. 关于 ACTION_MOVE 和 ACTION_UP 消息传递流程

上面讲解的都是 ACTION_DOWN 消息的传递流程,我们知道 ACTION_DOWN 之后,是 ACTION_MOVE, 最后是 ACTION_UP 。
这两者与 ACTION_DOWN 的消息传递并不完全一样。

因为 ACTION_MOVE 和 ACTION_UP 的消息流向是完全一样的,所以只讲 ACTION_MOVE。

4.1 在 dispatchTouchEvent 方法中返回 true 的消息传递流程

结论:
在 dispatchTouchEvent 方法中返回 true 拦截消息后, ACTION_MOVE 消息的流向与 ACTION_DOWN 完全相同,消息会直接停止传递,后面的子控件都不会接收到这个消息。

4.1 在 onTouchEvent 方法中返回 true 的消息传递流程

这部分很复杂,稍后补充。

ACTION_MOVE 消息总结:

  • 在 dispatchTouchEvent 方法中返回 true,拦截消息后, ACTION_MOVE 消息的流向与 ACTION_DOWN 消息的完全相同,消息会直接停止传递,后面的子控件都不会接收到这个消息。

  • 无论 ACTION_DOWN 的最终流向如何,只要最终流到 onTouchEvent 方法中就行。假设控件 A 最终在 onTouchEvent 方法中消费了 ACTION_DOWN 消息,那么 ACTION_MOVE 消息的流向就是先流到控件 A 的 dispatchTouchEvent 方法中,最终直接流到控件 A 的 onTouchEvent 方法中。进而消息停止传递。

事件传递流程

Activity -> PhoneWindow -> DecorView -> ViewGroup -> ... -> view

典型的责任链模式

如果最后的view也没有消费事件,那么事件就会被依次向上回传直到Activity,如果Activity也没有处理该事件,那么事件就被抛弃。
既保证了事件的有序性,又非常的灵活。

参考文献

《Android自定义控件高级进阶与精彩实例》

Link to post
Link to comment
Share on other sites

 Share

discussion group

discussion group

    You don't have permission to chat.
    • Recently Browsing   0 members

      • No registered users viewing this page.
    ×
    ×
    • Create New...