又遇到过监听事件无效的情况,然后找了一些资料。在这里做点笔记方便以后忘了复习!
一,先看一段代码:我自定义一个MyButton继承Button,并重写了dispatchTouchEvent(...)方法,onTouchEvent(...)方法
package com.example.getmynumber.view;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.Button;
public class MyButton extends Button{
public MyButton(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public MyButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
Log.i("wangsongbin", "dispatchTouchEvent:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.i("wangsongbin", "dispatchTouchEvent:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.i("wangsongbin", "dispatchTouchEvent:ACTION_UP");
break;
}
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i("wangsongbin", "onTouchEvent:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.i("wangsongbin", "onTouchEvent:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.i("wangsongbin", "onTouchEvent:ACTION_UP");
break;
}
return super.onTouchEvent(event);
}
}
在xml文件中引用
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.getmynumber.view.MyButton
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="hello touchEvent"/>
</RelativeLayout>
在Activity中为其绑定监听器
package com.example.getmynumber.activity.textview;
import com.example.getmynumber.R;
import com.example.getmynumber.view.MyButton;
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;
public class TouchEventTestActivity extends Activity{
private MyButton mButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_touchtest);
mButton=(MyButton) findViewById(R.id.btn);
mButton.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
Log.i("wangsongbin", "onTouch:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.i("wangsongbin", "onTouch:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.i("wangsongbin", "onTouch:ACTION_UP");
break;
}
return false;
}
});
}
}
我适当的擦了一下MyButton控件,结果如下:
可一个看到一个执行顺序:dispatchTouchEvent(...) ,触摸监听touch(...),onTouchEvent(...)
其实我们看一下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)) { //监听器onTouch(...)方法的执行位置
return true;
}
if (onTouchEvent(event)) { //onTouchEvnent(...)方法的执行位置。
return true;
}
}
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
}
return false;
}
我们可以很明显的看到监听器的onTouch方法的执行位置在onTouchEvent执行方法的前面。而且我还可以看到,如果li(即控件所有
监听器的封装类)不为null,li.mTouchListener(我们设置的触摸监听)不为null, 控件的状态为Enable,触摸监听的onTouch方法
返回true(即触摸事件被消耗掉),我们的onTouchEvent方法可能执行不了。
二,onClickListener,与onLongClickListener
在这里我重新为MyButton添加了onClickListener和onLongClickListener监听。然后我手指放下,稍稍等一会再拿起来。
package com.example.getmynumber.activity.textview;
import com.example.getmynumber.R;
import com.example.getmynumber.view.MyButton;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
public class TouchEventTestActivity extends Activity{
private MyButton mButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_touchtest);
mButton=(MyButton) findViewById(R.id.btn);
mButton.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
Log.i("wangsongbin", "onTouch:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.i("wangsongbin", "onTouch:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.i("wangsongbin", "onTouch:ACTION_UP");
break;
}
return false;
}
});
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.i("wangsongbin", "onClick:ACTION_UP");
}
});
mButton.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
Log.i("wangsongbin", "onLongClick:ACTION_UP");
return false;
}
});
}
}
我特地把Action_MOVE去掉,不然很难看到效果。所以去掉后看到的结果是!
onLongClick方法在Action_Down之后,Action_UP之前就执行了。
这段逻辑在onTouchEvent中:
onLongClick的执行途径:
Action_DWON时会启动一个115ms延迟的任务,如果115后如果还没有触发Action_up,则继续启动一个500-115ms的延迟任务
如果500ms后,则执行onLongClick方法。
onClick的执行途径:
在Action_Dwon是标PrePressed,如果在115~500ms内,触发了Action_up则执行onClick方法。
如果在500ms以后触发了Action_up,
1,onLongClickListener.onLongClick(...)返回true,则不会执行onClickListener.onClick(...),
2,onLongClickListener.onLongClick(...)返回false,则依然会执行onClickListener.onClick(...)