基础知识
- 所有的触摸事件(TouchEvent)都被被封装成了MotionEvent对象,它包含了这个事件的触摸位置、发生事件、历史纪录以及singleTouch、doubleTouch等等
- MotionEvent一般可以有以下几种行为类型 (ev.getAction()) ACTION_DOWN按下、ACTION_MOVE移动、ACTION_UP抬起、ACTION_POINTER_DOWN单点按下、ACTION_POINTER_UP单点抬起、ACTION_CANCEL取消,
- 每个事件都是以ACTION_DOWN开始ACTION_UP结束的
- 对事件的处理主要有下面三个函数 dispatchTouchEvent()、view.setOnTouchListener( onTouch())、onTouchEvent()
代码看看:
自定义一个button
package com.ostea.day1010;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.Button;
public class EventButton extends Button {
private static final String TAG = EventButton.class.getSimpleName();
public EventButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i(TAG, "dispatchTouchEvent ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.i(TAG, "dispatchTouchEvent ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.i(TAG, "dispatchTouchEvent ACTION_UP");
break;
default:
break;
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i(TAG,"onTouchEvent ACTION_DOWN" );
break;
case MotionEvent.ACTION_MOVE:
Log.i(TAG,"onTouchEvent ACTION_MOVE" );
break;
case MotionEvent.ACTION_UP:
Log.i(TAG,"onTouchEvent ACTION_UP" );
break;
default:
break;
}
return super.onTouchEvent(event);
}
}
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" >
<com.ostea.day1010.EventButton
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_centerInParent="true"
android:text="evnetbtn" />
</RelativeLayout>
MainActivity.java
package com.ostea.day1010;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
public class MainActivity extends ActionBarActivity {
String TAG = "EventButton";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn).setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View arg0, MotionEvent arg1) {
switch (arg1.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i(TAG, "onTouch ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.i(TAG, "onTouch ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.i(TAG, "onTouch ACTION_UP");
break;
default:
break;
}
return false;
}
});
}
}
结果
10-10 10:26:45.519: I/EventButton(8909): dispatchTouchEvent ACTION_DOWN
10-10 10:26:45.519: I/EventButton(8909): onTouch ACTION_DOWN
10-10 10:26:45.519: I/EventButton(8909): onTouchEvent ACTION_DOWN
10-10 10:27:04.744: I/EventButton(8909): onTouchEvent ACTION_MOVE
10-10 10:27:04.761: I/EventButton(8909): dispatchTouchEvent ACTION_MOVE
10-10 10:27:04.761: I/EventButton(8909): onTouch ACTION_MOVE
10-10 10:26:45.607: I/EventButton(8909): dispatchTouchEvent ACTION_UP
10-10 10:26:45.607: I/EventButton(8909): onTouch ACTION_UP
10-10 10:26:45.607: I/EventButton(8909): onTouchEvent ACTION_UP
可以看到所有事件始终以 ACTION_DWON开始 ----ACTION_UP结束
传递的顺序始终是 dispatchTouchEvent---> setOnTouchListener的onTouch--->onTouchEvent
为什么顺序是这样的? 看看源码。
public boolean dispatchTouchEvent(MotionEvent event) {
// 事件是否第一时间处理
if (event.isTargetAccessibilityFocus()) {
// 假如view没有获取焦点则不处理该事件,继续向下分发
if (!isAccessibilityFocusedViewOrHost()) {
return false;
}
// 当有获取焦点那么按照正常的事件奋发机制分发下去就可以
event.setTargetAccessibilityFocus(false);
}
boolean result = false;
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onTouchEvent(event, 0);
}
final int actionMasked = event.getActionMasked();
if (actionMasked == MotionEvent.ACTION_DOWN) {
// Defensive cleanup for new gesture
stopNestedScroll();
}
if (onFilterTouchEventForSecurity(event)) {
//noinspection SimplifiableIfStatement
ListenerInfo li = mListenerInfo;
//当view已经有触摸监听的时候,这个事件消费掉,并且这个事件接口回调view.setOntouchListener处理
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
//当在程序中没有对view进行人为的事件监听,那么会走onTouchEvent()方法
if (!result && onTouchEvent(event)) {
result = true;
}
}
....
也就是说在事件分发的时候会对其进行判断,当我们在程序中对view已经有事件监听操作的时候,那么事件MotionEvent会交给程序中的监听事件处理,否则交给onTouchEvent()处理。
在onClickListener() onLongClickLisetner(), 先直行长按事件,然后看其是否return false,假如返回为真则事件消费掉,屏蔽onClickListener,