您的位置:首页 > 移动开发 > Android开发

onTouchEvent用法解释以及触摸事件的传递机制

2012-04-24 17:55 274 查看
近期有一个项目有联系到重写View的,并且对View的触摸事件的控制有很高的要求,以前对onTouchEvent()方法还是有一点了解的,但是对一个View树之中的传递机制不是很了解。今天就来写个test程序来探究一下。

首先来概述一下onTouchEvent()这个方法的作用

SDK这样介绍:

public boolean onTouchEvent (MotionEvent event)

Since: API Level 1

Implement this method to handle touch screen motion events.


Parameters

eventThe motion event.

Returns


True if the event was handled, false otherwise.

我们可以很清楚理解他的含义,我们通常通过诸如
switch (event.getAction())

{
case MotionEvent.ACTION_DOWN:
……//控制代码
break;
case MotionEvent.ACTION_MOVE:
……//控制代码
break;
case MotionEvent.ACTION_UP:
……//控制代码
break;

}

之类的语句来控制对触摸的事件的响应。

值得注意的是返回值的作用 sdk 的含义是 返回“true”意味着你接手(handled)了这个“event”的控制,并且这个“event”不会向其他对象传递,而是自己“消化”掉。这个我们可以通过代码来验证。有一个很关键的问题我没有说,就是这个“event”来自于哪里,是直接来自于事件最开始的分配(个人认为android系统中有个一个控制触摸事件的机制,他控制了事件的第一次的发送)呢?还是来自于其他的对象(父结点或者子结点)的传递呢?于是我做了一个实验,这里先把结果告诉大家,事件由最上层的View(子节点)开始(第一次)接受,并将触摸事件逐层向父节点传递(除非某一个节点消化了这个事件)。

下面贴一下代码:
布局文件:main.xml
<?xml version="1.0" encoding="utf-8"?>
<com.yp.touchtest.Layout_one xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<com.yp.touchtest.Layout_two
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<com.yp.touchtest.View_one
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
</com.yp.touchtest.View_one>
</com.yp.touchtest.Layout_two>
</com.yp.touchtest.Layout_one>
其中 com.yp.touchtest.Layout_one和  com.yp.touchtest.Layout_two是重写的两个LinearLayout, com.yp.touchtest.View_one 重写了View.

Avtivity类:TouchTestActivity.class

public class TouchTestActivity extends Activity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}


Layout_one  Layout_two View_one 均只重写了 onTouchEvent(MotionEvent event) 方法

首先说明一下,所有情况 采用的触摸的手势均为 “按下”  -->"滑动" -->"抬起" 共3步。

情况一:3个对象均不消化触摸事件,即3个对象的onTouchEvent 不论什么情况都返回“false”。

View_one Layout_one 和 Layout_two 均重写为
@Override
public boolean onTouchEvent(MotionEvent event)
{
String name ="onTouchEvent  ";
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
System.out.println(Tag+name+"ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println(Tag+name+"ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println(Tag+name+"ACTION_UP");
break;
}
return false;
}


其中System.out.println(Tag+name+"ACTION_DOWN"); 打印语句中 Tag 为该类的类名(比如“View_one”),
name为方法名,此时3个类都一样为“onTouchEvent” 。

运行之后的结果为:
04-24 17:08:37.296: I/System.out(23225): View_one:  onTouchEvent  ACTION_DOWN

04-24 17:08:37.296: I/System.out(23225): layout_two:  onTouchEvent  ACTION_DOWN

04-24 17:08:37.296: I/System.out(23225): layout_one:  onTouchEvent  ACTION_DOWN

分析:我们可以清楚的看到 触摸事件的传递顺序为子节点-->父节点。让人惊讶的是,3个对象都没有接受到 move和up事件。原因的大家可以想一下,先向下看,答案自然揭晓。

情况二:基于情况一的代码, 把View_out类中的  的ACTION_DOWN事件 中返回“true”。

case MotionEvent.ACTION_DOWN:
System.out.println(Tag+name+"ACTION_DOWN");
return true;


运行之后的结果为:

04-24 17:18:17.921: I/System.out(23323): View_one:  onTouchEvent  ACTION_DOWN

04-24 17:18:17.944: I/System.out(23323): View_one:  onTouchEvent  ACTION_MOVE
04-24 17:18:18.030: I/System.out(23323): View_one:  onTouchEvent  ACTION_MOVE

……好多ACTION_MOVE

04-24 17:18:18.061: I/System.out(23323): View_one:  onTouchEvent  ACTION_MOVE

04-24 17:18:18.077: I/System.out(23323): View_one:  onTouchEvent  ACTION_MOVE

04-24 17:18:18.108: I/System.out(23323): View_one:  onTouchEvent  ACTION_UP

分析:  ACTION_DOWN 中返回了true 但是ACTION_DOWN都返回了false . 让人惊讶的是
 ACTION_DOWN  ACTION_MOVE ACTION_UP 3个事件都由View_one处理了。结合情况一,我们可以知道只要有一个对象接手(handled)了这个“event“的ACTION_DOWN事件 就会处理完这个事件,并且连同ACTION_MOVEACTION_UP  都”消化“掉。

情况三: 也是给予情况一的代码,把Layout_two的ACTION_MOVE事件返回“true”

运行之后的结果为: 
04-24 18:21:41.249: I/System.out(23605): View_one:  onTouchEvent  ACTION_DOWN

04-24 18:21:41.249: I/System.out(23605): layout_two:  onTouchEvent  ACTION_DOWN

04-24 18:21:41.273: I/System.out(23605): layout_two:  onTouchEvent  ACTION_MOVE

04-24 18:21:41.303: I/System.out(23605): layout_two:  onTouchEvent  ACTION_MOVE

……好多ACTION_MOVE,省略了

04-24 18:21:41.405: I/System.out(23605): layout_two:  onTouchEvent  ACTION_MOVE

04-24 18:21:41.444: I/System.out(23605): layout_two:  onTouchEvent  ACTION_UP

分析:这个情况更加印证了情况二分析的结论,这个情况中 Layout_one 处理并 “消化”了这个3事件 并且没有传递给他的父节点。

总结:
重写onTouchEvent() 这个方法,我们可以对用户的触摸事件进行处理。
触摸事件的传递方向为从子节点传向他的父节点,直到有一个结点返回了true
ACTION_DOWN  ACTION_MOVE  ACTION_UP  此时可以看作一个整体(其实不是)只要对ACTION_DOWN处理时返回了
true 就会把3个事件都处理并“消化”,不传递给他的父节点。
 

以后我会对和onTouchEvent(MotionEvent event)一个比较相关的方法  onInterceptTouchEvent(MotionEvent ev)做一写相关的实验。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐