Android事件分发机制和触摸反馈

前言

首先,Android系统为什么会定义一套事件分发机制?
其实很简单,因为我们的布局里面View,ViewGroup是树状结构,一组事件顺序流过来,到底是View处理还是ViewGroup处理,都是在Android 事件分发机制下运行的,有了Android事件分发机制我们可以有效避免事件冲突,或者是可以很方便的自定义触摸反馈。


Android事件分发机制

机制下的核心类

public final class MotionEvent extends InputEvent implements Parcelable {

    /**
     * Constant for {@link #getActionMasked}: A pressed gesture has started, the
     * motion contains the initial starting location.
     * 

* This is also a good time to check the button state to distinguish * secondary and tertiary button clicks and handle them appropriately. * Use {@link #getButtonState} to retrieve the button state. *

*/ public static final int ACTION_DOWN = 0; /** * Constant for {@link #getActionMasked}: A pressed gesture has finished, the * motion contains the final release location as well as any intermediate * points since the last down or move event. */ public static final int ACTION_UP = 1; /** * Constant for {@link #getActionMasked}: A change has happened during a * press gesture (between {@link #ACTION_DOWN} and {@link #ACTION_UP}). * The motion contains the most recent point, as well as any intermediate * points since the last down or move event. */ public static final int ACTION_MOVE = 2; /** * Constant for {@link #getActionMasked}: The current gesture has been aborted. * You will not receive any more points in it. You should treat this as * an up event, but not perform any action that you normally would. */ public static final int ACTION_CANCEL = 3; //省略非核心代码 ...... }

机制下的核心方法

  • dispatchTouchEvent()
  • onInterceptTouchEvent()
  • onTouchEvent()

机制的关键知识点

  • Activity最顶层的Window是PhoneWindow,PhoneWindow最顶层的View是DecorView,DecorView是继承FrameLayout,DecorView下面是一个LinearLayout,
    LinearLayout下面有两个子View,两个子View都是继承FrameLayout。
  • 一个clickable或者longClickable的View会永远消费Touch事件。
  • 长按事件是在ACTION_DOWN事件中执行的,要想执行长按事件该View必须设置longClickable,然后通过OnLongClickListener回调给上层应用处理,期间不能产生ACTION_MOVE事件。
  • 点击事件是在ACTION_UP事件中执行的,前提是消费了ACTION_DOWN事件,并且没有设置OnLongClickListener的情况下,如设置了OnLongClickListener的情况,则必须使onLongClick()返回false。
  • 如果View设置了onTouchListener了,并且onTouch()方法返回true,则不执行View的onTouchEvent()方法,也表示View消费了Touch事件,返回false则继续执行onTouchEvent()。
  • 事件流分发过程中,子View如果处理了ACTION_DOWN事件,但是后面的事件流里面的事件被父View,在onInterceptTouchEvent中被拦截,那么父View 就接管后面的事件流,并且向处理了ACTION_DOWN的子View发送一个ACTION_CANCEL事件。

触摸反馈

  • 对于触摸反馈,一般是我们在自定义View的时候,在Android事件分发机制下,来使用,比如我们需要在自定义的View里面做自己的触发算法,这个时候需要重写View的onTouchEvent方法,在里面写上你的触摸反馈算法,并返回 true(关键是 ACTION_DOWN 事件时返回 true。
  • 如果是会发生触摸冲突的 ViewGroup,还需要重写 onInterceptTouchEvent(),在事件流开始时返回 false,并在确认接管事件流时返回一次 true,以实现对事件的拦截。
  • 当子 View 临时需要父View 拦截事件流时,可以调用父 View 的 requestDisallowInterceptTouchEvent() ,通知父 View 在当前事件流中不再尝试通过 onInterceptTouchEvent() 来拦截。

你可能感兴趣的:(Android事件分发机制和触摸反馈)