Android 触摸事件分发过程
来源:互联网 发布:java快速开发框架 编辑:程序博客网 时间:2024/06/05 18:21
前言
这是demo 链接
Android 中 View 的事件传递是一个老生常谈的问题,但也是学习 Android 的重点和难点。本人将分三篇来分享 Android 中的事件传递。
- 通过 demo 分析 Android 事件的传递过程
- 通过源码分析 Android 事件的传递过程
- 运用所学解决 Android 中滑动冲突
MotionEvent
Android 中事件的传递其实传递的就是 MotionEvent 对象。MotionEvent 中封装了事件的各种状态和属性。最常用的最典型的有如下几种:
- ACTION_DOWN ———————手指刚接触屏幕
- ACTION_MOVE ———————手指在屏幕上移动
- ACTION_UP ———————手指从屏幕上松开的一瞬间
Android 事件传递相关方法
- public boolean dispatchTouchEvent(MotionEvent ev) 负责事件的分发
- public boolean onInterceptTouchEvent(MotionEvent ev) 负责事件拦截
- public boolean onTouchEvent(MotionEvent event) 负责事件的处理
在 ViewGroup 中有上述三个方法,但是在 View 中没有 onInterceptTouchEvent 方法。因为 View 没有子 View,所以就不牵扯到事件的拦截。
编写 demo
自定义相关 View
由于 LinearLayout 继承 ViewGroup,我们只需新建类 CustomLinearLayout 继承 LinearLayout。重写上述三个方法,如下
@Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: Log.i(TAG, "======dispatchTouchEvent======ACTION_DOWN=="); break; case MotionEvent.ACTION_MOVE: Log.i(TAG, "======dispatchTouchEvent======ACTION_MOVE=="); break; case MotionEvent.ACTION_UP: Log.i(TAG, "======dispatchTouchEvent======ACTION_UP=="); break; } return super.dispatchTouchEvent(ev);} @Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: Log.i(TAG, "======onInterceptTouchEvent======ACTION_DOWN=="); break; case MotionEvent.ACTION_MOVE: Log.i(TAG, "======onInterceptTouchEvent======ACTION_MOVE=="); break; case MotionEvent.ACTION_UP: Log.i(TAG, "======onInterceptTouchEvent======ACTION_UP=="); break; } return super.onInterceptTouchEvent(ev);} @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: Log.i(TAG, "======onTouchEvent======ACTION_DOWN=="); break; case MotionEvent.ACTION_MOVE: Log.i(TAG, "======onTouchEvent======ACTION_MOVE=="); break; case MotionEvent.ACTION_UP: Log.i(TAG, "======onTouchEvent======ACTION_UP=="); break; } return super.onTouchEvent(event);}
同样的新建类 CustomTextView 继承 TextView,重写 dispatchTouchEvent 和 onTouchEvent。同样重写 MainActivity 中的 dispatchTouchEvent 和 onTouchEvent。
布局文件
<com.cuifei.test.CustomLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <com.cuifei.test.CustomButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="CustomButton" />
查看运行结果
事件分发 Log
由图事件分发 Log 可以看出 ACTION_DOWN 传递的顺序示意图,如下图:
Android 事件分发示意图
在这之间我们并没有消费事件,由此可以看到事件从最外层逐级向内层传递,如果在这之间事件没有被消费掉,事件将由内层控件逐级向外层控件传递。
以 ACTION_DOWN 为例,详细分析 Android 事件传递的流程。 首先,MainActivity 捕获到 ACTION_DOWN 事件,并由 MainActivity 的 dispatchTouchEvent 方法分发给其子控件。因为 CustomLinearLayout 是 MainActivity 的子控件(我们暂且这么认为),所以 ACTION_DOWN 被分发给 CustomLinearLayout 并由 CustomLinearLayout 的 dispatchTouchEvent 继续分发。由于 CustomLinearLayout 是 ViewGroup 能够对事件进行拦截,所以 ACTION_DOWN 被分发给 CustomLinearLayout 的 onInterceptTouchEvent 方法。如果 onInterceptTouchEvent 返回 true 则拦截,否则不拦截。这里 CustomLinearLayout 的 onInterceptTouchEvent 返回 false,不对 ACTION_DOWN 拦截。所以 ACTION_DOWN 继续被分发给 CustomLinearLayout 的子控件 CustomTextView ,并由 CustomTextView 的 dispatchTouchEvent 进行分发。因为 CustomTextView 是 View 并且是最内层的 View ,所以 ACTION_DOWN 被分发给 CustomTextView 的 onTouchEvent 方法进行处理。本 demo 中 ACTION_DOWN 没有被 CustomTextView 的 onTouchEvent 处理掉,所以 ACTION_DOWN 向上传递给 CustomLinearLayout 的 onTouchEvent 。而 CustomLinearLayout 的 onTouchEvent 也没有处理 ACTION_DOWN,所以 ACTION_DOWN 继续向上传递给 MainActivity 的 onTouchEvent 。而 MainActivity 的 onTouchEvent 也没有处理,至此 ACTION_DOWN 将被释放,ACTION_DOWN 事件分发结束。
由图 事件分发 Log 我们还可以看出,ACTION_MOVE 和 ACTON_UP 并没有向内层控件传递,而是由 MainActivity 自己分发和处理。这说明 ACTION_MOVE 和 ACTON_UP 只传递到消费 ACTION_DOWN 的控件。为了验证这个我们将 CustomLinearLayout.onTouchEvent 的返回值改为 true 表示事件被 CustomLinearLayout 处理。
事件拦截Log
由 事件拦截Log可以看出 ACTION_MOVE 和 ACIONT_UP 只传递到了 CustomLinearLayout 这说明我们的上述观点是正确的。
由上面的代码可以看到和 onTouchEvent 方法一样,dispatchTouchEvent 和 onInterceptTouchEvent 方法也有一个 boolean 类型的返回值,这个返回值分别代表什么意思呢?
- onInterceptTouchEvent 返回值为 true 时;表示事件被拦截,不在向内层控件传递。反之则向内层控件传递。
- dispatchTouchEvent 返回 true 表示事件被 dispatchTouchEvent 自身处理消耗掉。至此,事件已经完结;返回 false 不再继续进行分发,并交由上层控件的onTouchEvent 方法进行处理;返回 super.dispatchTouchEvent(ev) 时,事件将继续传递。
最后两条结论的 log 将不再贴出,请读者自己验证。
最后给出本 demo 中事件分发的详细流程图,如下图:
Android 事件分发流程图
- Android 触摸事件分发过程
- Android 触摸事件分发
- Android触摸事件分发
- Android 触摸事件分发
- Android 从源码分析 Android 触摸事件分发过程
- Android触摸事件分发机制
- Android触摸事件分发机制
- Android触摸事件分发机制
- Android触摸事件分发机制
- Android触摸事件分发机制
- Android触摸事件分发机制
- Android触摸事件分发机制
- Android触摸事件分发机制
- android触摸事件分发机制
- android触摸事件分发机制
- Android触摸事件分发机制
- Android触摸事件分发机制
- Android触摸事件分发机制
- 贪心算法初探 “今年暑假不AC
- 数据报转发子模块对数据报的操作
- ThinkPHP 使用表单令牌遇到的问题
- 错误: 编码GBK的不可映射字符
- android LinearLayout布局嵌套覆盖问题
- Android 触摸事件分发过程
- nodejs常见坑【01】——安装express
- Linux下安装Oracle的jdk1.8
- SPL的常用迭代器(3)
- 递归算法与迭代算法总结
- nodejs gb2312、GBK中文乱码解决方法
- Java与模式:装饰(Decorator)模式
- SPL基础接口(4)
- JavaScript学习笔记——数据类型