转载请注明出处:http://blog.csdn.net/xiaohao0724/article/details/54780880
Android中事件分发和事件传递是一个难点牵涉的东西较多,下面我们就由浅入深一点一点来给解析事件的分发和传递机制。
在分析事件的机制之前需要大家了解如下知识:
Android所有控件的父控件都是View和ViewGroup
ViewGroup继承了View
Button、EditText、TextView、ImageView等都继承了View
RelativeLayout、LinearLayout、FrameLayout、TableLayout、AbsoulteLayout五大布局继承了ViewGroup
事件处理机制主要通过dispatchTouchEvent方法来处理,当触摸到了任何一个控件,就一定会调用该控件(或该控件的父类)的dispatchTouchEvent方法
View是根据dispatchTouchEvent的返回值进行事件分发的,当返回true时响应所有事件,事件的分发事件停止。
public boolean dispatchTouchEvent(MotionEvent event) {
return false/true;
}
ViewGroup根据onInterceptTouchEvent的返回值判断是否去拦击事件进行事件传递的,返回true拦截事件不向子控件传递,返回false是不拦截传递给子控件
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false/true;
}
View中dispatchTouchEvent的完整方法
public boolean dispatchTouchEvent(MotionEvent event) {
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}
当给View设置了setOnTouchListener之后
①mOnTouchListener != null 恒成立②(mViewFlags & ENABLED_MASK) == ENABLED 恒成立
③mOnTouchListener.onTouch(this, event) 跟 setOnTouchListener中回调的onTouch的返回值相同
首先新建一个EventView工程:
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:gravity="center"
tools:context=".MainActivity" >
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:background="@drawable/ic_launcher" />
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/imageView"
android:layout_marginTop="30dp"
android:gravity="center"
android:text="点击" />
</RelativeLayout>
MainActivity.java代码
package com.havorld.eventview;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.ImageView;
public class MainActivity extends Activity {
protected static final String TAG = "TAG";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView imageView = (ImageView) findViewById(R.id.imageView);
Button button = (Button) findViewById(R.id.button);
imageView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// event.getAction()返回0是按下down,返回1是抬起up,返回2是移动move
Log.e(TAG, "imageView---onTouch---" + event.getAction());
return true;
}
});
button.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.e(TAG, "button ---onTouch---" + event.getAction());
return true;
}
});
}
}
一、对ImageView进行事件分发分析
原因分析:
看源码找到控件的父类View中的dispatchTouchEvent方法
当onTouch返回true时dispatchTouchEvent返回true,响应所有的事件。此时不调用onTouchEvent方法。
当onTouch返回false时将调用onTouchEvent方法,dispatchTouchEvent中的返回值与onTouchEvent的返回值相同,查看onTouchEvent方法知当控件的clickable = false时onTouchEvent返回的返回为false(默认情况下ImageView的clickable = false),即dispatchTouchEvent返回false 不响应所有事件(所有事件指得是按下、滑动、抬起事件)。
此时再给ImageView设置一个点击事件:
imageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.e(TAG, "imageView---onClick");
}
});
当 setOnTouchListener回掉的 onTouch方法返回true时
当onTouch方法返回false时:
原因分析:
对于onTouch方法的事件分析:
看源码找到控件的父类View中的dispatchTouchEvent方法
当onTouch返回true时dispatchTouchEvent返回true,onTouch方法响应所有的事件
当onTouch返回false时调用onTouchEvent方法,dispatchTouchEvent中的返回值与onTouchEvent的返回值相同(给ImageView设置setOnClickListener事件后其clickable = true)onTouchEvent返回值为true,即dispatchTouchEvent返回true响应所有事件。
对于onClick方法的事件分析:
查看源码知onClick方法是在onTouchEvent方法里面的performClick()方法做的回调
当onTouch返回true时dispatchTouchEvent返回true,不调用onTouchEvent方法,所以不调用onTouchEvent方法里面的performClick()方法,所以不响应onClick事件(可理解成onTouch返回true时事件被onTouch消费掉了不再传递给onClick方法)
当onTouch返回false时调用onTouchEvent方法,调用onTouchEvent方法里面的performClick()方法,所以响应onClick事件
当 onTouch方法返回false时:
二、对Button进行事件分发分析
其它分析过程同ImageView,请各位看客个自行分析咯。
总结一下:
先给ImageView设置setOnTouchListener、setOnClickListener方法。
当点击并滑动ImageView时,先调用其父类View中的dispatchTouchEvent,此时对dispatchTouchEvent中的条件进行判断,
①当onTouch方法返回true时,dispatchTouchEvent方法直接返回true(因为mOnTouchListener != null 、 (mViewFlags & ENABLED_MASK) == ENABLED方法恒成立)不再调用onTouchEvent方法,此时响应onTouch方法中的所有事件,由于onClick方法是在onTouchEvent方法中的回调所以onClick方法不再执行。
②当onTouch方法返回false时,dispatchTouchEvent方法调用onTouchEvent方法并与onTouchEvent的返回值相同,onTouchEvent又回调了performClick()方法,performClick()方法又回调了onClick所以执行onClick方法。在源码中可以看出onTouchEvent的返回值跟控件clickable 的返回值相同,默认情况下ImageView的clickable = false,在设置了setOnClickListener事件后其clickable = true,所以onTouchEvent返回值为true,dispatchTouchEvent的返回值为true,onTouch响应所有事件。
Button的自己总结下哈。
OK,是不是觉得很简单,后面的文章我们将对一些复杂的情况进行分析