新建一个类MyButton,该类继承自Button
然后重写其中的onTouchEvent和dispatchTouchEvent方法
public class MyButton extends Button {
private Context mContext;
public MyButton(Context context) {
super(context);
this.mContext = context;
}
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d("TTTT", "context:" + mContext + "MyButton|dispatchTouchEvent|return:" + super.dispatchTouchEvent(event) + "|event:DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.d("TTTT", "context:" + mContext + "MyButton|dispatchTouchEvent|return:" + super.dispatchTouchEvent(event) + "|event:MOVE");
break;
case MotionEvent.ACTION_UP:
Log.d("TTTT", "context:" + mContext + "MyButton|dispatchTouchEvent|return:" + super.dispatchTouchEvent(event) + "|event:UP");
break;
}
Log.d("TTTT", "========================== ");
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d("TTTT", "context:" + mContext + "MyButton|onTouchEvent|return:" + super.onTouchEvent(event) + "|event:DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.d("TTTT", "context:" + mContext + "MyButton|onTouchEvent|return:" + super.onTouchEvent(event) + "|event:MOVE");
break;
case MotionEvent.ACTION_UP:
Log.d("TTTT", "context:" + mContext + "MyButton|onTouchEvent|return:" + super.onTouchEvent(event) + "|event:UP");
break;
}
return super.onTouchEvent(event);
}
}
然后将这个Button加入到布局文件中,然后在Activity中给这个Button设置一个onTouchListener
<LinearLayout 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="com.example.testtouchevent.MainActivity" >
<com.example.testtouchevent.MyButton
android:id="@+id/bt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="按钮" />
</LinearLayout>
public class MainActivity extends Activity {
private Button bt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt = (Button) findViewById(R.id.bt);
bt.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return false;
}
});
}
}
按下按钮时候,log显式
03-31 11:51:08.493: D/TTTT(1609): context:com.example.testtouchevent.MainActivity@528486ecMyButton|onTouchEvent|return:true|event:DOWN
03-31 11:51:08.493: D/TTTT(1609): context:com.example.testtouchevent.MainActivity@528486ecMyButton|dispatchTouchEvent|return:true|event:DOWN
03-31 11:51:08.493: D/TTTT(1609): ==========================
03-31 11:51:08.493: D/TTTT(1609): context:com.example.testtouchevent.MainActivity@528486ecMyButton|onTouchEvent|return:true|event:DOWN
松开按钮时候,log显式:
03-31 11:51:10.285: D/TTTT(1609): context:com.example.testtouchevent.MainActivity@528486ecMyButton|onTouchEvent|return:true|event:UP
03-31 11:51:10.285: D/TTTT(1609): context:com.example.testtouchevent.MainActivity@528486ecMyButton|dispatchTouchEvent|return:true|event:UP
03-31 11:51:10.285: D/TTTT(1609): ==========================
03-31 11:51:10.289: D/TTTT(1609): context:com.example.testtouchevent.MainActivity@528486ecMyButton|onTouchEvent|return:true|event:UP
可见onTouchEvent方法是在dispatchTouchEvent方法之前执行的
可是View的事件传递机制不是dispatchTouchEvent方法先执行用来传递消息的吗?
请问这是怎么回事儿?
应该是button是最后一层,没有子类了,事件传递是向子类传递,如果没有子类就会调用onTouchEvent方法
首先,button的enabled默认为true,那么在没有OnTouchListener或者有OnTouchListener但是返回false的时候,会第一时间传递给onTouchEvent,
第二,当前Button是最后一级,没有子类可派发事件
public class MyButton extends Button {
。。。。。省略代码。。。。。。
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d("TTTT", "context:" + mContext + "MyButton|dispatchTouchEvent|return:" + super.dispatchTouchEvent(event) + "|event:DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.d("TTTT", "context:" + mContext + "MyButton|dispatchTouchEvent|return:" + super.dispatchTouchEvent(event) + "|event:MOVE");
break;
case MotionEvent.ACTION_UP:
Log.d("TTTT", "context:" + mContext + "MyButton|dispatchTouchEvent|return:" + super.dispatchTouchEvent(event) + "|event:UP");
break;
}
Log.d("TTTT", "========================== ");
return super.dispatchTouchEvent(event);
}
。。。。。省略代码。。。。。。
}
onTouchEvent方法会在dispatchTouchEvent方法之前执行是因为你在打印日志的时候调用了super.super.dispatchTouchEvent(event)
即在DOWN和UP打印日志的代码:
Log.d("TTTT", "context:" + mContext + "MyButton|dispatchTouchEvent|return:" + super.dispatchTouchEvent(event) + "|event:DOWN");
Log.d("TTTT", "context:" + mContext + "MyButton|dispatchTouchEvent|return:" + super.dispatchTouchEvent(event) + "|event:UP");
这时候会调用MyButton的父类View的dispatchTouchEvent方法
public boolean dispatchTouchEvent(MotionEvent event) {
// If the event should be handled by accessibility focus first.
if (event.isTargetAccessibilityFocus()) {
// We don't have focus or no virtual descendant has it, do not handle the event.
if (!isAccessibilityFocusedViewOrHost()) {
return false;
}
// We have focus and got the event, then use normal event dispatch.
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)) {
if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
result = true;
}
//noinspection SimplifiableIfStatement
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) {
result = true;
}
}
if (!result && mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
}
// Clean up after nested scrolls if this is the end of a gesture;
// also cancel it if we tried an ACTION_DOWN but we didn't want the rest
// of the gesture.
if (actionMasked == MotionEvent.ACTION_UP ||
actionMasked == MotionEvent.ACTION_CANCEL ||
(actionMasked == MotionEvent.ACTION_DOWN && !result)) {
stopNestedScroll();
}
return result;
}
这个时候就调用了MyButton的onTouchEvent方法会先打印 onTouchEvent的日志
然后再打印 dispatchTouchEvent 日志,在MyButton#dispatchTouchEvent 最后又return super.dispatchTouchEvent(event);
打印你添加的分割线: Log.d("TTTT", "========================== ");
这时又会调用MyButton的onTouchEvent再打印一次 onTouchEvent的日志
最终得日志就变成了
03-31 11:51:08.493: D/TTTT(1609): context:com.example.testtouchevent.MainActivity@528486ecMyButton|onTouchEvent|return:true|event:DOWN
03-31 11:51:08.493: D/TTTT(1609): context:com.example.testtouchevent.MainActivity@528486ecMyButton|dispatchTouchEvent|return:true|event:DOWN
03-31 11:51:08.493: D/TTTT(1609): ==========================
03-31 11:51:08.493: D/TTTT(1609): context:com.example.testtouchevent.MainActivity@528486ecMyButton|onTouchEvent|return:true|event:DOWN
更详细内容我写了一篇文章:https://blog.csdn.net/u011288271/article/details/114395637