从源码角度带你分析 Android View 事件分发 dispatchTouchEvent

关于Android View 事件分发过程的文章网络上可以搜到一把大,这里贴一篇代码性的文章,作者也是个牛人:Android事件分发机制完全解析,带你从源码的角度彻底理解(上)。

虽然讲的很好,但是看完之后还是感觉有那么点一知半解,于是自己花了点时间从源码研究android 触摸事件分发流程,以下内容仅仅个人理解,如有差错希望指出。

我们先从一个例子看起,先重写一个MyButton 继承Button,代码如下:

public class MyButton extends Button {public MyButton(Context context) {super(context);}public MyButton(Context context, AttributeSet attrs) {super(context, attrs);}public MyButton(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overridepublic boolean dispatchTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:MyLog.e("dispatchTouchEvent====MyButton=====ACTION_DOWN");break;case MotionEvent.ACTION_MOVE:MyLog.e("dispatchTouchEvent====MyButton=====ACTION_MOVE");break;case MotionEvent.ACTION_UP:MyLog.e("dispatchTouchEvent====MyButton=====ACTION_UP");break;}return super.dispatchTouchEvent(event);}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:MyLog.e("onTouchEvent====MyButton=====ACTION_DOWN");break;case MotionEvent.ACTION_MOVE:MyLog.e("onTouchEvent====MyButton=====ACTION_MOVE");break;case MotionEvent.ACTION_UP:MyLog.e("onTouchEvent====MyButton=====ACTION_UP");break;}return super.onTouchEvent(event);}

布局文件如下:<RelativeLayout xmlns:android=""xmlns: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=".MainActivity"><com.xjp.testtouchevent.MyButtonandroid:id="@+id/myButton"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="测试" /></RelativeLayout>测试Activity如下:public class MainActivity extends ActionBarActivity {private Button myButton;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);myButton = (Button) findViewById(R.id.myButton);myButton.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:MyLog.e("onTouch====MyButton=====ACTION_DOWN");break;case MotionEvent.ACTION_MOVE:MyLog.e("onTouch====MyButton=====ACTION_MOVE");break;case MotionEvent.ACTION_UP:MyLog.e("onTouch====MyButton=====ACTION_UP");break;}return false;}});myButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {MyLog.e("onClick====MyButton=====onClick");}});}}

点击测试按钮,打印结果如下:

我们从打印结果可以直观看到,点击Button按钮事件分发过程如下dispatchTouchEvent—->onTouch—->onTouchEvent—–>onClick。并且如果仔细的你会发现,都是在ACTION_UP事件之后才触发onClick点击事件,为什么会是这样??现在我们不得而知。我们仅仅是从打印结果推测事件分发的结论,现在我们从源码分析下这个事件分发流程为什么是这样子。

事件分发都是从dispatchTouchEvent方法开始的,那么我们这里是重写了dispatchTouchEvent方法,并且最后也调用了父类的super.dispatchTouchEvent(event)方法。那么我们看看父类中的方法到底做了什么??点击进入父类的dispatchTouchEvent方法,发现此方法在View类中找到,其实也不奇怪,所有控件的父类都是View。这里我贴出最新源码如下:

public boolean dispatchTouchEvent(MotionEvent event) {boolean result = false;if (mInputEventConsistencyVerifier != null) {mInputEventConsistencyVerifier.onTouchEvent(event, 0);}final int actionMasked = event.getActionMasked();if (actionMasked == MotionEvent.ACTION_DOWN) {// Defensive cleanup for new gesturestopNestedScroll();}if (onFilterTouchEventForSecurity(event)) {//noinspection SimplifiableIfStatementListenerInfo 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.setOnTouchListener事件(Button 的onTouch事件),在MainActivity代码里,我们

人生谁无少年时,甜苦酸辛各自知。

从源码角度带你分析 Android View 事件分发 dispatchTouchEvent

相关文章:

你感兴趣的文章:

标签云: