1、案例
为了更好的研究View的事件转发,我们自定以一个MyButton继承Button,然后把跟事件传播有关的方法进行复写,然后添加上日志~
MyButton
- 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中打印了日志~
然后把我们自定义的按钮加到主布局文件中;
布局文件:
- <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的代码
- 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;
下面我们运行,然后点击按钮,查看日志输出:
- 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。