为了更好的研究View的事件转发,我们自定以一个MyButton继承Button,然后把跟事件传播有关的方法进行复写,然后添加上日志~
MyButton
[java] view plain copy package com.example.zhy_event03; 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 { private static final String TAG = MyButton.class.getSimpleName(); public MyButton(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: Log.e(TAG, "onTouchEvent ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.e(TAG, "onTouchEvent ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.e(TAG, "onTouchEvent ACTION_UP"); break; default: break; } return super.onTouchEvent(event); } @Override public boolean dispatchTouchEvent(MotionEvent event) { int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: Log.e(TAG, "dispatchTouchEvent ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.e(TAG, "dispatchTouchEvent ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.e(TAG, "dispatchTouchEvent ACTION_UP"); break; default: break; } return super.dispatchTouchEvent(event); } } 在onTouchEvent和dispatchTouchEvent中打印了日志~
然后把我们自定义的按钮加到主布局文件中;
布局文件:
[html] view plain copy <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" tools:context=".MainActivity" > <com.example.zhy_event03.MyButton android:id="@+id/id_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="click me" /> </LinearLayout> 最后看一眼MainActivity的代码
[java] view plain copy package com.example.zhy_event03; 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; public class MainActivity extends Activity { protected static final String TAG = "MyButton"; private MyButtonmButton ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mButton = (MyButton) findViewById(R.id.id_btn); mButton.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: Log.e(TAG, "onTouch ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.e(TAG, "onTouch ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.e(TAG, "onTouch ACTION_UP"); break; default: break; } return false; } }); } } 在MainActivity中,我们还给MyButton设置了OnTouchListener这个监听~
好了,跟View事件相关一般就这三个地方了,一个onTouchEvent,一个dispatchTouchEvent,一个setOnTouchListener;
下面我们运行,然后点击按钮,查看日志输出:
[html] view plain copy 08-31 06:09:39.030: E/MyButton(879): dispatchTouchEvent ACTION_DOWN 08-31 06:09:39.030: E/MyButton(879): onTouch ACTION_DOWN 08-31 06:09:39.049: E/MyButton(879): onTouchEvent ACTION_DOWN 08-31 06:09:39.138: E/MyButton(879): dispatchTouchEvent ACTION_MOVE 08-31 06:09:39.138: E/MyButton(879): onTouch ACTION_MOVE 08-31 06:09:39.147: E/MyButton(879): onTouchEvent ACTION_MOVE 08-31 06:09:39.232: E/MyButton(879): dispatchTouchEvent ACTION_UP 08-31 06:09:39.248: E/MyButton(879): onTouch ACTION_UP 08-31 06:09:39.248: E/MyButton(879): onTouchEvent ACTION_UP 我有意点击的时候蹭了一下,不然不会触发MOVE,手抖可能会打印一堆MOVE的日志~~~
好了,可以看到,不管是DOWN,MOVE,UP都会按照下面的顺序执行:
1、dispatchTouchEvent
2、 setOnTouchListener的onTouch
3、onTouchEvent
下面就跟随日志的脚步开始源码的探索
首先判断mOnTouchListener不为null,如果return true就不会有onTouchEvent事件了
OnTouchListen>onTouchEvent>OnClickListen。点击事件是最后执行的
总结整个View的事件转发流程是:
View.dispatchEvent->View.setOnTouchListener->View.onTouchEvent
在dispatchTouchEvent中会进行OnTouchListener的判断,如果OnTouchListener不为null且返回true,则表示事件被消费,onTouchEvent不会被执行;否则执行onTouchEvent到OnClickListen。
