android 全方位理解TouchEvent

来源:互联网 发布:360比价软件 编辑:程序博客网 时间:2024/05/29 02:32
关于TouchEvent涉及下面三个方法:
public boolean dispatchTouchEvent(MotionEvent ev);    //分派event
public boolean onInterceptTouchEvent(MotionEvent ev); //拦截event
public boolean onTouchEvent(MotionEvent ev);          //处理event

先不管dispatchTouchEvent如何分派,先运行代码测试效果。
activity_main.xml:
<RelativeLayout 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"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    tools:context=".MainActivity"     android:id = "@+id/layout">    <com.example.test.MyLinearLayout        android:layout_width="match_parent"   android:layout_height="match_parent">        <com.example.test.MyButton        android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:text = "@string/button"/>    </com.example.test.MyLinearLayout></RelativeLayout>

MainActivity.java:
public class MainActivity extends Activity {public static final String TAG = "MainActivity"; @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}@Overridepublic boolean onTouchEvent(MotionEvent event) {Log.e(TAG, "MainActivity onTouchEvent default return " + super.onTouchEvent(event)); return super.onTouchEvent(event);}}

MyLinearLayout.java:
public class MyLinearLayout extends LinearLayout {public static final String TAG = "MyLinearLayout";public MyLinearLayout(Context context, AttributeSet attrs) {super(context, attrs);// TODO Auto-generated constructor stub}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {// TODO Auto-generated method stubLog.e(TAG, "MyLinearLayout onInterceptTouchEvent default return " + super.onInterceptTouchEvent(ev));return super.onInterceptTouchEvent(ev);}@Overridepublic boolean onTouchEvent(MotionEvent event) {// TODO Auto-generated method stubLog.e(TAG, "MyLinearLayout onTouchEvent default return " + super.onTouchEvent(event));return super.onTouchEvent(event);}}

MyButton.java:
public class MyButton extends Button{public static final String TAG = "MyButton";public MyButton(Context context, AttributeSet attrs) {super(context, attrs);// TODO Auto-generated constructor stub}@Overridepublic boolean onTouchEvent(MotionEvent event) {Log.e(TAG, "MyButton onTouchEvent default return " + super.onTouchEvent(event));return super.onTouchEvent(event);}}


效果为:


点击按钮后,首先产生MotionEvent.ACTION_DOWN事件,MyLinearLayout的onInterceptTouchEvent方法尝试截取event,由于default return false(不截取),轮到MyButton处理,default return true处理成功,完成。然后还会产生MotionEvent.ACTION_UP事件,同样的过程。
注意:MyLinearLayout的onInterceptTouchEvent是继承与ViewGroup的onInterceptTouchEvent,而onTouchEvent是继承与View的onTouchEvent;而MyButton的onTouchEvent是继承与TextView的onTouchEvent。所以他们的default return不一样。

如果使MyButton中的onTouchEvent返回false。情况会如何呢?MyButton的onTouchEvent代码改成下面:
@Overridepublic boolean onTouchEvent(MotionEvent event) {Log.e(TAG, "MyButton onTouchEvent return false");return false;}

结果为:

同样的,点击按钮后,首先产生MotionEvent.ACTION_DOWN事件,MyLinearLayout的onInterceptTouchEvent方法尝试截取event,由于default return false(不截取),轮到MyButton处理,return false不处理。这时候,event会交给MyButton的上级View(MyLInearLayout)的onTouchEvent进行处理,还是return false,没办法,只能由MainActivity自己处理。然后还会产生MotionEvent.ACTION_UP事件,但这个事件没有交给MyLinearLayout和MyButton处理,而是MainActivity处理,为什么?一个连续事件(如点击产生练两个事件ACTION_DOWN和ACTION_UP)处理的特点,当第一个事件(ACTION_DOWN)处理后,这个例子MyButton、MyLinearLayout不去处理,那么后续事件(ACTION_UP)就不会再交他们处理了,直接是MainActivity处理。

如果让MyLInearLayout的onInterceptTouchEvent返回true,前面说了,它用于拦截event,也就是不让event传到下一级,我们看代码:
@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {// TODO Auto-generated method stubLog.e(TAG, "MyLinearLayout onInterceptTouchEvent  return true");return true;}
结果请看:

可以看到效果了吧,MyButton没有出现,因为event被MyLInearLayout拦截了,拦截之后交给它的onTouchEvent处理了,但是它的onTouchEvent不给力,return false,因此,只能由老大MainActivity处理。而MotionEvent.ACTION_UP还是由MainActivity处理,这应该知道了吧,对于连续事件中的第一个事件下级没能力处理,后续event都不会传下去。

那我把MyLinearLayout的onTouchEvent也改成返回true。看代码:
@Overridepublic boolean onTouchEvent(MotionEvent event) {// TODO Auto-generated method stubLog.e(TAG, "MyLinearLayout onTouchEvent default return true" );return true;}
情况会怎样呢? 看答案:

都明白了吧,ACTION_DOWN由MyLInearLayout处理,ACTION_UP也由它来处理。
还有其他情况就不一一试了,大家有兴趣再玩一下。

===================================================先隔开一下========================================================================
下面简单说一下event的分派过程,这时候就要用到dispatchTouchEvent

Activity有这个方法,View也有,那是当然的,不然怎么分派,然后子类就可以用dispatchTouchEvent方法了。本例的分派过程如下:

event----->MainActivity------调用它的dispatchTouchEvent方法分派event------>

MyLinearLayout-------调用它的dispatchTouchEvent-----------如果不拦截(如果拦截看上面)---------->

MyButton------------调用它的dispatchTouchEvent----------->onTouchEvent处理,return false咋办?看上面


就说这么简单!!


再补充一个上面的处理event都是基于回调进行的,android还有一种监听的方法,需要设置onTouchListener。那两种方法有什么区别呢,到底会使用哪一种呢?先看一下View里的dispatchTouchEvent怎么写,学一下哈:

public boolean dispatchTouchEvent(MotionEvent event) {        if (mInputEventConsistencyVerifier != null) {            mInputEventConsistencyVerifier.onTouchEvent(event, 0);        }        if (onFilterTouchEventForSecurity(event)) {            //noinspection SimplifiableIfStatement            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;            }        }        if (mInputEventConsistencyVerifier != null) {            mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);        }        return false;    }


懒人看一下8、9、10和14行吧哈

上面的代码大体意思是:在dispatchTouchEvent方法中判断是否用了onTouchListener对象的onTouch方法处理,如果onTouch返回true,那回调方法onTouchEvent没有机会处理了,如果没有设置shionTouchListener或onTouch返回false,就由onTouchEvent处理。


内置诸如click事件的实现等等都基于onTouchEvent,假如onTouch返回true,这些事件将不会被触发。

文章烂尾了哈,希望大家喜欢。



0 0