您的位置:首页 > 其它

触摸事件对应的消息响应

2015-06-08 10:47 288 查看
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,这些事件将不会被触发。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: