Android View 事件分发机制 源码解析 (上)

一直想写事件分发机制的文章,不管咋样,也得自己研究下事件分发的源码,写出心得~

首先我们先写个简单的例子来测试View的事件转发的流程~

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);}@Overridepublic 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);}@Overridepublic 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=""xmlns:tools=""android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity" ><com.example.zhy_event03.MyButtonandroid: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 Button mButton ;@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mButton = (Button) findViewById(R.id.id_btn);mButton.setOnTouchListener(new OnTouchListener(){@Overridepublic 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_DOWN08-31 06:09:39.030: E/MyButton(879): onTouch ACTION_DOWN08-31 06:09:39.049: E/MyButton(879): onTouchEvent ACTION_DOWN08-31 06:09:39.138: E/MyButton(879): dispatchTouchEvent ACTION_MOVE08-31 06:09:39.138: E/MyButton(879): onTouch ACTION_MOVE08-31 06:09:39.147: E/MyButton(879): onTouchEvent ACTION_MOVE08-31 06:09:39.232: E/MyButton(879): dispatchTouchEvent ACTION_UP08-31 06:09:39.248: E/MyButton(879): onTouch ACTION_UP08-31 06:09:39.248: E/MyButton(879): onTouchEvent ACTION_UP我有意点击的时候蹭了一下,,不然不会触发MOVE,手抖可能会打印一堆MOVE的日志~~~

好了,可以看到,不管是DOWN,MOVE,UP都会按照下面的顺序执行:

1、dispatchTouchEvent

2、setOnTouchListener的onTouch

3、onTouchEvent

下面就跟随日志的脚步开始源码的探索~

2、dispatchTouchEvent

首先进入View的dispatchTouchEvent

/*** Pass the touch screen motion event down to the target view, or this* view if it is the target.** @param event The motion event to be dispatched.* @return True if the event was handled by the view, false otherwise.*/public boolean dispatchTouchEvent(MotionEvent event) {if (!onFilterTouchEventForSecurity(event)) {return false;}if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&mOnTouchListener.onTouch(this, event)) {return true;}return onTouchEvent(event);}直接看13行:首先判断mOnTouchListener不为null,并且view是enable的状态,然后mOnTouchListener.onTouch(this, event)返回true,这三个条件如果都满足,直接return true ; 也就是下面的onTouchEvent(event)不会被执行了;是不是因为心痛的麻木了,我才笑得最美丽。

Android View 事件分发机制 源码解析 (上)

相关文章:

你感兴趣的文章:

标签云: