触摸事件对应的消息响应
2015-06-08 10:47
351 查看
1. OnInterceptTouchEvent是viewGroup的方法,事件是从父控件一直向子控件传递的(寻找最终的ontouchevent响应者),但是OnInterceptTouchEvent可以在这个传递的过程中由某一层的控件截获事件,不让其往下传,截获后,只要在这一层的控件中覆写ontouchevent并返回true,表示这一层控件已经消费了这个事件
2 ViewGroup的OnInterceptTouchEvent返回true,则这一层控件的ontouchevent会调用,OnInterceptTouchEvent返回false,不会调用这一层的ontouchevent,事件传给子控件,如果子控件消费了此事件,并在ontouchevent中返回false,则会返回父控件的ontouchevent调用,直到某一层控件的ontouchevent返回true
3. onInterceptTouchEvent返回值代表是截获此事件交给本级别ontouchevent处理,还是不截获而直接交给子控件处理,ontouchevent返回值代表是否把此事件传给父控件处理
4.activity也有ontouchevent方法,没有OnInterceptTouchEvent方法,每次触摸事件中,如果最终没有ontouchevent返回true,最后会调用activity的ontouchevent
5. 触控事件首先触发action_down, action_down在哪一级控件响应,则后续的action_move,action_up的响应控件一定和action_down一样,action_down最终在哪一级控件的ontouchevent消费掉(返回true),后续的action_move,action_up会按层级传递到这一级控件的ontouchevent处理(这一级之上的OnInterceptTouchEvent肯定都是返回了false,都会调用,这一级的OnInterceptTouchEvent在后续的up,move事件中将不调用),但是如果down事件中,最终最上层的子控件的ontouchevent都是返回fasle的,这样
会在activity的ontouchevent中响应,后续的move,up等事件直接会由activity的ontouchevent处理,不会调用其他层级的OnInterceptTouchEvent和ontouchevent了
6. View(非viewgroup)是没有OnInterceptTouchEvent方法的,OnInterceptTouchEvent默认返回false,所以默认情况下,最上层的子控件(直接接触触控的控件)肯定会调用其ontouchevent的,ontouchevent默认返回false,所以默认情况下,最上层子控件调用完ontouchevent,会依次返回上层的控件去调用ontouchevent
7. 一次触摸事件包括down,move,up三个过程(如果快速触摸,可能没有move),所以每次触摸,会有2-3次对OnInterceptTouchEvent和ontouchevent的逻辑判断调用
示例:
下面用一个简单的实验说明上述复杂的规则。视图自底向上共3层,其中LayoutView1和LayoutView2就是LinearLayout, MyTextView就是TextView:
对应的xml布局文件如下:
<?xml version="1.0" encoding="utf-8"?>
<com.touchstudy.LayoutView1xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<com.touchstudy.LayoutView2
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center">
<com.touchstudy.MyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tv"
android:text="AB"
android:textSize="40sp"
android:textStyle="bold"
android:background="#FFFFFF"
android:textColor="#0000FF"/>
</com.touchstudy.LayoutView2>
</com.touchstudy.LayoutView1>
1. onInterceptTouchEvent()处理down事件均返回false,onTouchEvent()处理事件均返回true
------------------------------------------------------------------------------------------------------------------------------
04-11 03:58:42.620: DEBUG/LayoutView1(614): onInterceptTouchEventaction:ACTION_DOWN
04-11 03:58:42.620: DEBUG/LayoutView2(614): onInterceptTouchEventaction:ACTION_DOWN
04-11 03:58:42.620: DEBUG/MyTextView(614): onTouchEvent action:ACTION_DOWN
04-11 03:58:42.800: DEBUG/LayoutView1(614): onInterceptTouchEventaction:ACTION_MOVE
04-11 03:58:42.800: DEBUG/LayoutView2(614): onInterceptTouchEventaction:ACTION_MOVE
04-11 03:58:42.800: DEBUG/MyTextView(614): onTouchEvent action:ACTION_MOVE
…… //省略过多的ACTION_MOVE
04-11 03:58:43.130: DEBUG/LayoutView1(614): onInterceptTouchEventaction:ACTION_UP
04-11 03:58:43.130: DEBUG/LayoutView2(614): onInterceptTouchEventaction:ACTION_UP
04-11 03:58:43.150: DEBUG/MyTextView(614): onTouchEvent action:ACTION_UP
------------------------------------------------------------------------------------------------------------------------------
这 是最常见的情况,onInterceptTouchEvent并没有做任何改变事件传递时序的操作,效果上和没有覆写该方法是一样的。可以看到,各种事件的传递本身是自底向上的,次序是:LayoutView1->LayoutView2->MyTextView。注意,在onInterceptTouchEvent均返回false时,LayoutView1和LayoutView2的onTouchEvent并不会收到事件,而是最终传递给了MyTextView。
2. LayoutView1的onInterceptTouchEvent()处理down事件返回true,
MyTextView的onTouchEvent()处理事件返回true
------------------------------------------------------------------------------------------------------------------------------
04-11 03:09:27.589: DEBUG/LayoutView1(446): onInterceptTouchEventaction:ACTION_DOWN
04-11 03:09:27.589: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_DOWN
04-11 03:09:27.629: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_MOVE
04-11 03:09:27.689: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_MOVE
…… //省略过多的ACTION_MOVE
04-11 03:09:27.959: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_UP
------------------------------------------------------------------------------------------------------------------------------
从Log可以看到,由于LayoutView1在拦截第一次down事件时return true,所以后续的事件(包括第一次的down)将由LayoutView1本身处理,事件不再传递下去。
3. LayoutView1,LayoutView2的onInterceptTouchEvent()处理down事件返回false,
MyTextView的onTouchEvent()处理事件返回false
LayoutView2的onTouchEvent()处理事件返回true
----------------------------------------------------------------------------------------------------------------------------
04-11 09:50:21.147: DEBUG/LayoutView1(301): onInterceptTouchEvent action:ACTION_DOWN
04-11 09:50:21.147: DEBUG/LayoutView2(301): onInterceptTouchEventaction:ACTION_DOWN
04-11 09:50:21.147: DEBUG/MyTextView(301): onTouchEvent action:ACTION_DOWN
04-11 09:50:21.147: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_DOWN
04-11 09:50:21.176: DEBUG/LayoutView1(301): onInterceptTouchEventaction:ACTION_MOVE
04-11 09:50:21.176: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_MOVE
04-11 09:50:21.206: DEBUG/LayoutView1(301): onInterceptTouchEventaction:ACTION_MOVE
04-11 09:50:21.217: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_MOVE
…… //省略过多的ACTION_MOVE
04-11 09:50:21.486: DEBUG/LayoutView1(301): onInterceptTouchEventaction:ACTION_UP
04-11 09:50:21.486: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_UP
----------------------------------------------------------------------------------------------------------------------------
可 以看到,由于MyTextView在onTouchEvent()中return false,down事件被传递给其父view,即LayoutView2的onTouchEvent()方法处理,由于在LayoutView2的 onTouchEvent()中return true,所以down事件传递并没有上传到LayoutView1。注意,后续的move和up事件均被传递给LayoutView2的 onTouchEvent()处理,而没有传递给MyTextView。
Android View的onTouchEvent和OnTouch区别:
还是以自定义的TestButton为例。
我们可以通过重写onTouchEvent方法来处理诸如down move up的消息:
[java] view
plaincopyprint?
public class TestButton extends Button {
public TestButton(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public TestButton(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
// TODO Auto-generated constructor stub
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean value = super.onTouchEvent(event);
System.out.println("super.onTouchEvent: " + value+ " event: " + event.getAction());
return value;
}
也可以通过实现OnTouchListener的接口,然后设置TestButton的onTouchListener可以达到同样的目的
[java] view
plaincopyprint?
class OnTouchListenerTest implements View.OnTouchListener{
@Override
public boolean onTouch(View v, MotionEvent event) {
return false;
}
}
[java] view
plaincopyprint?
TestButton b = (TestButton)findViewById(R.id.button);
OnTouchListenerTest listener = new OnTouchListenerTest();
b.setOnTouchListener(listener);
但上述两种监听有什么区别呢?
先看一下Android源码中对于View中dispatchTouchEvent的实现:
[java] view
plaincopyprint?
public boolean dispatchTouchEvent(MotionEvent event){
... ...
if(onFilterTouchEventForSecurity(event)){
ListenerInfo li = mListenerInfo;
if(li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
return true;
}
if(onTouchEvent(event)){
return true;
}
}
... ...
return false;
}
可以看到onTouchListener的接口的优先级是要高于onTouchEvent的,假若onTouchListener中的onTouch方法返回true,
表示此次事件已经被消费了,那onTouchEvent是接收不到消息的。
因为Button的performClick是利用onTouchEvent实现,假若onTouchEvent没有被调用到,那么Button的Click事件也无法响应。
综合来讲:
onTouchListener的onTouch方法优先级比onTouchEvent高,会先触发。
假如onTouch方法返回false会接着触发onTouchEvent,反之onTouchEvent方法不会被调用。
内置诸如click事件的实现等等都基于onTouchEvent,假如onTouch返回true,这些事件将不会被触发。
2 ViewGroup的OnInterceptTouchEvent返回true,则这一层控件的ontouchevent会调用,OnInterceptTouchEvent返回false,不会调用这一层的ontouchevent,事件传给子控件,如果子控件消费了此事件,并在ontouchevent中返回false,则会返回父控件的ontouchevent调用,直到某一层控件的ontouchevent返回true
3. onInterceptTouchEvent返回值代表是截获此事件交给本级别ontouchevent处理,还是不截获而直接交给子控件处理,ontouchevent返回值代表是否把此事件传给父控件处理
4.activity也有ontouchevent方法,没有OnInterceptTouchEvent方法,每次触摸事件中,如果最终没有ontouchevent返回true,最后会调用activity的ontouchevent
5. 触控事件首先触发action_down, action_down在哪一级控件响应,则后续的action_move,action_up的响应控件一定和action_down一样,action_down最终在哪一级控件的ontouchevent消费掉(返回true),后续的action_move,action_up会按层级传递到这一级控件的ontouchevent处理(这一级之上的OnInterceptTouchEvent肯定都是返回了false,都会调用,这一级的OnInterceptTouchEvent在后续的up,move事件中将不调用),但是如果down事件中,最终最上层的子控件的ontouchevent都是返回fasle的,这样
会在activity的ontouchevent中响应,后续的move,up等事件直接会由activity的ontouchevent处理,不会调用其他层级的OnInterceptTouchEvent和ontouchevent了
6. View(非viewgroup)是没有OnInterceptTouchEvent方法的,OnInterceptTouchEvent默认返回false,所以默认情况下,最上层的子控件(直接接触触控的控件)肯定会调用其ontouchevent的,ontouchevent默认返回false,所以默认情况下,最上层子控件调用完ontouchevent,会依次返回上层的控件去调用ontouchevent
7. 一次触摸事件包括down,move,up三个过程(如果快速触摸,可能没有move),所以每次触摸,会有2-3次对OnInterceptTouchEvent和ontouchevent的逻辑判断调用
示例:
下面用一个简单的实验说明上述复杂的规则。视图自底向上共3层,其中LayoutView1和LayoutView2就是LinearLayout, MyTextView就是TextView:
对应的xml布局文件如下:
<?xml version="1.0" encoding="utf-8"?>
<com.touchstudy.LayoutView1xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<com.touchstudy.LayoutView2
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center">
<com.touchstudy.MyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tv"
android:text="AB"
android:textSize="40sp"
android:textStyle="bold"
android:background="#FFFFFF"
android:textColor="#0000FF"/>
</com.touchstudy.LayoutView2>
</com.touchstudy.LayoutView1>
1. onInterceptTouchEvent()处理down事件均返回false,onTouchEvent()处理事件均返回true
------------------------------------------------------------------------------------------------------------------------------
04-11 03:58:42.620: DEBUG/LayoutView1(614): onInterceptTouchEventaction:ACTION_DOWN
04-11 03:58:42.620: DEBUG/LayoutView2(614): onInterceptTouchEventaction:ACTION_DOWN
04-11 03:58:42.620: DEBUG/MyTextView(614): onTouchEvent action:ACTION_DOWN
04-11 03:58:42.800: DEBUG/LayoutView1(614): onInterceptTouchEventaction:ACTION_MOVE
04-11 03:58:42.800: DEBUG/LayoutView2(614): onInterceptTouchEventaction:ACTION_MOVE
04-11 03:58:42.800: DEBUG/MyTextView(614): onTouchEvent action:ACTION_MOVE
…… //省略过多的ACTION_MOVE
04-11 03:58:43.130: DEBUG/LayoutView1(614): onInterceptTouchEventaction:ACTION_UP
04-11 03:58:43.130: DEBUG/LayoutView2(614): onInterceptTouchEventaction:ACTION_UP
04-11 03:58:43.150: DEBUG/MyTextView(614): onTouchEvent action:ACTION_UP
------------------------------------------------------------------------------------------------------------------------------
这 是最常见的情况,onInterceptTouchEvent并没有做任何改变事件传递时序的操作,效果上和没有覆写该方法是一样的。可以看到,各种事件的传递本身是自底向上的,次序是:LayoutView1->LayoutView2->MyTextView。注意,在onInterceptTouchEvent均返回false时,LayoutView1和LayoutView2的onTouchEvent并不会收到事件,而是最终传递给了MyTextView。
2. LayoutView1的onInterceptTouchEvent()处理down事件返回true,
MyTextView的onTouchEvent()处理事件返回true
------------------------------------------------------------------------------------------------------------------------------
04-11 03:09:27.589: DEBUG/LayoutView1(446): onInterceptTouchEventaction:ACTION_DOWN
04-11 03:09:27.589: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_DOWN
04-11 03:09:27.629: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_MOVE
04-11 03:09:27.689: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_MOVE
…… //省略过多的ACTION_MOVE
04-11 03:09:27.959: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_UP
------------------------------------------------------------------------------------------------------------------------------
从Log可以看到,由于LayoutView1在拦截第一次down事件时return true,所以后续的事件(包括第一次的down)将由LayoutView1本身处理,事件不再传递下去。
3. LayoutView1,LayoutView2的onInterceptTouchEvent()处理down事件返回false,
MyTextView的onTouchEvent()处理事件返回false
LayoutView2的onTouchEvent()处理事件返回true
----------------------------------------------------------------------------------------------------------------------------
04-11 09:50:21.147: DEBUG/LayoutView1(301): onInterceptTouchEvent action:ACTION_DOWN
04-11 09:50:21.147: DEBUG/LayoutView2(301): onInterceptTouchEventaction:ACTION_DOWN
04-11 09:50:21.147: DEBUG/MyTextView(301): onTouchEvent action:ACTION_DOWN
04-11 09:50:21.147: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_DOWN
04-11 09:50:21.176: DEBUG/LayoutView1(301): onInterceptTouchEventaction:ACTION_MOVE
04-11 09:50:21.176: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_MOVE
04-11 09:50:21.206: DEBUG/LayoutView1(301): onInterceptTouchEventaction:ACTION_MOVE
04-11 09:50:21.217: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_MOVE
…… //省略过多的ACTION_MOVE
04-11 09:50:21.486: DEBUG/LayoutView1(301): onInterceptTouchEventaction:ACTION_UP
04-11 09:50:21.486: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_UP
----------------------------------------------------------------------------------------------------------------------------
可 以看到,由于MyTextView在onTouchEvent()中return false,down事件被传递给其父view,即LayoutView2的onTouchEvent()方法处理,由于在LayoutView2的 onTouchEvent()中return true,所以down事件传递并没有上传到LayoutView1。注意,后续的move和up事件均被传递给LayoutView2的 onTouchEvent()处理,而没有传递给MyTextView。
Android View的onTouchEvent和OnTouch区别:
还是以自定义的TestButton为例。
我们可以通过重写onTouchEvent方法来处理诸如down move up的消息:
[java] view
plaincopyprint?
public class TestButton extends Button {
public TestButton(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public TestButton(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
// TODO Auto-generated constructor stub
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean value = super.onTouchEvent(event);
System.out.println("super.onTouchEvent: " + value+ " event: " + event.getAction());
return value;
}
也可以通过实现OnTouchListener的接口,然后设置TestButton的onTouchListener可以达到同样的目的
[java] view
plaincopyprint?
class OnTouchListenerTest implements View.OnTouchListener{
@Override
public boolean onTouch(View v, MotionEvent event) {
return false;
}
}
[java] view
plaincopyprint?
TestButton b = (TestButton)findViewById(R.id.button);
OnTouchListenerTest listener = new OnTouchListenerTest();
b.setOnTouchListener(listener);
但上述两种监听有什么区别呢?
先看一下Android源码中对于View中dispatchTouchEvent的实现:
[java] view
plaincopyprint?
public boolean dispatchTouchEvent(MotionEvent event){
... ...
if(onFilterTouchEventForSecurity(event)){
ListenerInfo li = mListenerInfo;
if(li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
return true;
}
if(onTouchEvent(event)){
return true;
}
}
... ...
return false;
}
可以看到onTouchListener的接口的优先级是要高于onTouchEvent的,假若onTouchListener中的onTouch方法返回true,
表示此次事件已经被消费了,那onTouchEvent是接收不到消息的。
因为Button的performClick是利用onTouchEvent实现,假若onTouchEvent没有被调用到,那么Button的Click事件也无法响应。
综合来讲:
onTouchListener的onTouch方法优先级比onTouchEvent高,会先触发。
假如onTouch方法返回false会接着触发onTouchEvent,反之onTouchEvent方法不会被调用。
内置诸如click事件的实现等等都基于onTouchEvent,假如onTouch返回true,这些事件将不会被触发。
相关文章推荐
- ASP.net MVC4 AsyncController异步action无法异步执行?
- C++ tips: C++ Dark Corner 0 标准流格式化输出
- JavaScript中exec函数用法实例分析
- asp.net发送电子邮件
- Activity中的四种启动模式
- QT 中怎样使得控件与 界面等比例变化
- Activity中的四种启动模式
- String、StringBuffer与StringBuilder之间区别
- public,private,protected的区别
- 串口调试小节之一 串口硬件连线
- shell循环,for 、while、until
- VS2008 使用 occi 连接 Oracle 服务器- 不用安装客户端
- IOS界面(图片)翻转
- Jquery基础:append、prepend、after、before、appendTo的区别
- 美丽新香港
- Cocos2d-x 3.2:定时器的使用和原理探究(1)
- Codeforces Round #306 (Div. 2) D
- Spring DI和IoC区别
- Spring DI和IoC区别
- Spring DI和IoC区别