三个例子搞清楚触摸事件的传递以及发生

401 阅读2分钟

触摸反馈是触摸事件发生后给予的页面上的反馈。需要注意的是触摸事件的发生并不是独立出现的,是成序列的、成组的,并且以 Down 为开始,以 Up 或者 Cancel 为结束,中间会有 Move。Cancel 是非人为的触摸事件结束的时候会触发。

触摸事件关键点在两个函数,public boolean onTouchEvent(MotionEvent event)public boolean onInterceptTouchEvent(MotionEvent ev)

  • onInterceptTouchEvent 只在 ViewGroup 中。
  • onTouchEvent 在触摸事件产生的时候,会从顶部到底部依次触发。在 ACTION_DOWN 返回 true 时,后面接着的一系列事件(一直到 ACTION_UP 或 ACTION_CANCEL )就不继续向下传递,表示当前 View 接管此系列触摸事件。
  • onInterceptTouchEvent 是任意触摸事件由底向上传递过程中,当前ViewGroup是否拦截。返回 true 表示拦截。拦截之后交由当前的 onTouchEvent 进行处理并且会向当前在 onTouchEvent 中处理此触摸事件的 View 发送 ACTION_CANCEL 以恢复 View 的原始状态。
  • 调用父 View 的 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) 可以禁止父 View 拦截触摸事件。

例子一:

如上图,有这么一组布局,当我们点击 View_A 触发的是 View_A 的点击事件,而重叠的 View_C 的点击事件并不会被触发。当我们点击 View_B 时,触发的重叠的 View_C 的点击事件。

原因是在我们点击的过程中,由 onTouchEvent 处理我们的触摸事件。这个方法是由顶层向底层依次调用,所以会触发离我们最近的 View 的点击事件。

例子二:

如上图,有这么一组布局,当我们点击 View_A 触发的是 View_A 的点击事件,在 View_A 或 View_C 上面移动我们的手指,触发的是 View_C 滑动事件。把手指放在 View_A 上的一瞬间,会触发 View_A 的 ACTION_DOWN 方法,但是我们开始移动手指,因为没有提起手指,所以不会触发 View_A 的点击事件,此时 View_C 中的 onInterceptTouchEvent 方法发现我们的手指在移动,所以会拦截接下来的触摸事件,并且给 View_A 发送一个 ACTION_CANCEL 的事件, View_A 接收到 ACTION_CANCEL 会恢复原样(在 ACTION_DOWN 的时候可能会改变了当前的状态)。

例子三:

如上图所示,此时 View_A 不仅有点击事件,而且还能长按移动位置,并且 View_C 可以滑动。这时需要保证长按移动位置的过程不触发 View_C 的滑动事件就要调用父 View 的 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) 禁止 View_C 在长按移动的时候拦截触摸事件。