首页 > 代码库 > Android触摸事件分发机制完全解析《一》

Android触摸事件分发机制完全解析《一》

最近在做高德地图的时候,由于用户的要求,不得不用ScrollVew嵌套MapView,虽然很官方要求不建议这样做,但也迫于无奈… 魔高一尺,道高一丈.有什么事情事程序员不能解决的,如果有那就是解决两次.

鉴于用到了触摸事件,于是就来总结了Android的触摸事件机制.

首先当用户进行屏幕操作的时候,则有两种情况

  • 一是按键事件

  • 二是触摸事件

按键事件分为长按和点击事件,过于简单,这里不再进行总结.

触摸事件

触摸事件的组成:
- 一个actionDown
- n个actionMove
- 一个actionUp
- 一个onClick
- 一个onLongClick
- 一个onScroll

Android组件

  • 继承 ViewGroupo比如LinearLayout,ScrollView,GridView,extends–>ViewGroup的View
  • ViewGroup容器
  • 继承于 View不包含其他的View ,如TextView,Edittext,Butto等

下面介绍一个讲的好的一个博客地址:

http://www.trinea.cn/android/touch-event-delivery-mechanism/

MotionEvent

所有Touch事件都被封装成了MotionEvent对象,包括Touch的位置、时间、历史记录以及第几个手指(多指触摸)等。

Android 事件的处理的分类

  • 分发(很多人也称作为传递事件) : dispatchTouchEvent函数

  • 消费: onTouchEvent函数和OnTouchListener函数

  • 拦截:dispatchTouchEvent函数

我们都知道Android的触摸事件都是从外层传递到内层:由最外层的Activity——>ViewGroup——> ViewGroupo——>…….View.

第一触摸事件传递的开始一定是Activity;

第二传递方式是通过隧道方式传递;

第三一直传递到一个最外层的View,也就是顶级View,由该View的这个方法来进行分发。

对于Activity来说:


    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean isFlag = super.dispatchTouchEvent(ev);
        return isFlag;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean isFlag = super.onTouchEvent(event);
        return isFlag;
    }

对于ViewGroup来说:

  @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean isFlag =super.onTouchEvent(event);
        return  isFlag;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        boolean isFlag =super.onInterceptTouchEvent(event);
        return  isFlag;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        boolean isFlag =super.dispatchTouchEvent(event);
        return  isFlag;
    }

对于View来说和Activity一样,只有消费和拦截


    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean isFlag = super.dispatchTouchEvent(ev);
        return isFlag;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean isFlag = super.onTouchEvent(event);
        return isFlag;
    }

http://www.open-open.com/lib/view/open1463016891525.html

android中的Touch事件都是从ACTION_DOWN开始的:

单手指操作:ACTION_DOWN—ACTION_MOVE—-ACTION_UP

多手指操作:ACTION_DOWN—ACTION_POINTER_DOWN—ACTION_MOVE–ACTION_POINTER_UP—ACTION_UP.

如果都不进行拦截,都不消费的基本流程图:

技术分享

下面我们就用案例进行分析:

activity—-》ViewGroup(MyLinearLayout)—》ViewGroup(MySubView)

MyLinearLayout的dispatchTouchEvent返回false。

技术分享

打印结果:

技术分享

  • 过程及结果分析:

  • 事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分发给 TouchEventFather 控件的dispatchTouchEvent;

  • 而该TouchEventFather 控件的 dispatchTouchEvent 返回 false,表示对获取到的事件停止向下传递,同时也不对该事件进行消费;

  • 由于 TouchEventFather 获取的事件直接来自 TouchEventActivity ,则会将事件返回给 TouchEventActivity 的 onTouchEvent 进行消费;

  • 最后直接由 TouchEventActivity 来响应手指移动和抬起事件。

MyLinearLayout的dispatchTouchEvent返回true。

技术分享

打印结果:

技术分享

  • 过程及结果分析:

  • 事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分发给 TouchEventFather 控件的 dispatchTouchEvent;

  • 而该TouchEventFather 控件的 dispatchTouchEvent 返回 true,表示分发事件到 TouchEventFather 控件并由该控件的 dispatchTouchEvent 进行消费;

  • 又因为TouchEventActivity 不断的分发事件到 TouchEventFather 控件的 dispatchTouchEvent,而 TouchEventFather 控件的 dispatchTouchEvent 也不断的将获取到的事件进行消费。

MyLinearLayout的onInterceptTouchEvent返回true。

技术分享

打印结果:

技术分享

  • 过程及结果分析:

  • 事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分发给 TouchEventFather 控件的 dispatchTouchEvent;

  • 而该TouchEventFather 控件的 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev),表示对事件进行分发并向下传递给 TouchEventFather 控件的 onInterceptTouchEvent 方法;

  • 而该方法返回 true 表示对所获取到的事件进行拦截并将事件传递给 TouchEventFather 控件的 onTouchEvent 进行处理,TouchEventFather 控件的 onTouchEvent 返回 super.onTouchEvent(ev) 表示对事件没有做任何处理直接将事件返回给上级控件;

  • 由于 TouchEventFather 获取的事件直接来自 TouchEventActivity,所以 TouchEventFather 控件的 onTouchEvent 会将事件以冒泡方式直接返回给 TouchEventActivity 的 onTouchEvent 进行消费;

  • 后续的事件则会跳过 TouchEventFather 直接由 TouchEventActivity 的 onTouchEvent 消费来自 TouchEventActivity 自身分发的事件。

MyLinearLayout的onInterceptTouchEvent返回false。

技术分享

打印结果:

技术分享

  • 过程及结果分析:

  • 事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分发给 TouchEventFather 控件的 dispatchTouchEvent;

  • 而该控件的 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev),表示对事件进行分发并向下传递给 TouchEventFather 控件的 onInterceptTouchEvent 方法;

  • 该方法返回 false 表示事件会被放行并传递到子控件 TouchEventChilds 的 dispatchTouchEvent 方法;

  • 同样 TouchEventChilds 的 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev),表示对事件进行分发并向下传递给 TouchEventChilds 控件的 onInterceptTouchEvent 方法;

  • 而TouchEventChilds 的 onInterceptTouchEvent 方法返回 super.onInterceptTouchEvent(ev) ,默认会将事件传递给 TouchEventChilds 的 onTouchEvent 进行处理;

  • 而TouchEventChilds 的 onTouchEvent 返回 super.onTouchEvent(ev) 表示对事件没有做任何处理直接将事件返回给上级控件;

  • 由于 TouchEventChilds 获取的事件直接来自 TouchEventFather,所以 TouchEventChilds 控件的 onTouchEvent 会将事件以冒泡方式直接返回给 TouchEventFather 的 onTouchEvent 进行消费;

  • 而 TouchEventFather 的 onTouchEvent 也返回了 super.onTouchEvent(ev),同样 TouchEventFather 的 onTouchEvent 也会将事件返回给上级控件;

  • 而 TouchEventFather 获取的事件直接来自 TouchEventActivity,所以 TouchEventFather 控件的 onTouchEvent 会将事件以冒泡方式直接返回给 TouchEventActivity 的 onTouchEvent 进行消费;

  • 后续的事件则会跳过 TouchEventFather 和 TouchEventChilds 直接由 TouchEventActivity 的 onTouchEvent 消费来自 TouchEventActivity 自身分发的事件。

MyLinearLayout的onInterceptTouchEvent返回false。MySubView返回true

技术分享

打印结果:

技术分享

  • 过程及结果分析:

  • 事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分发给 TouchEventFather 控件的 dispatchTouchEvent;

  • 该控件的 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev),事件会分发到 TouchEventFather 的 onInterceptTouchEvent,此方法返回 false 表示放行当先事件;

  • 事件会被传递到子控件 TouchEventChilds 的 dispatchTouchEvent 方法,dispatchTouchEvent 返回 true 表示事件被分发到 TouchEventChilds ,并由 dispatchTouchEvent 方法消费;

  • 后续的事件也会不断的重复上面的逻辑最终被 TouchEventChilds 的 dispatchTouchEvent 消费。

其实如果看源码的话比较复杂,总结一下,基本的规则是:

  • down事件首先会传递到onInterceptTouchEvent()方法

  • 如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return false,内部view将也会获取到down,那么后续的move, up等事件将继续会先传递给该ViewGroup,之后一样传递给最终的目标view的onTouchEvent()处理。

  • 如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return true,内部view不会货到down,后续的move, up等事件也不再传递给onInterceptTouchEvent(),当然,move,up也不会传给view

  • 如果最终需要处理事件的view的onTouchEvent()返回了false,那么该事件将被传递至其上一层次的view的onTouchEvent()处理。

  • 如果最终需要处理事件的view 的onTouchEvent()返回了true,那么后续事件将可以继续传递给该view的onTouchEvent()处理。

  • group的touch和这个机制没关系,与上一级有关系。

来自androidstarjack博客地址:

http://blog.csdn.net/androidstarjack/article/details/71910168

如果你觉得此文对您有所帮助,欢迎入群 QQ交流群 :232203809 ??

微信公众号:终端研发部

技术分享

(欢迎关注学习和交流)

<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

    Android触摸事件分发机制完全解析《一》