首先引入一个前提:Android 系统是的事件分发是通过控件的 dispatchTouchEvent (MotionEvent event) 方法进行的。
一、View.dispatchTouchEvent
从源码分析得知,事件分发过程有三次被消耗的机会,分别是 Scrollbar、listener 和 View 自己。如果仍不能被消耗,则返回 false 表示事件未被消耗。
二、onTouchEvent
首先看框架,仍然有三次被消耗的机会,最后一次才会自己试着消耗。
特别注意:第三次 View 自己消耗的时候,如果 View 可点击,则一定被消耗。
三、事件消耗
特别感谢 @鸿洋_ 老师 的博客
1、ACTION_DOWN
作为一切事件的开始,做一些准备工作:清空 mHasPerformedLongPress,根据是否在滚动容器内,启动误触检测(mPendingChechForTap)或者直接启动长按检测(chechForLongClick)。
分别看一下 CheckForTap 和 CheckForLongClick
115ms 后,设置 pressed,同时启动检测长按。
如果消耗长按,则设置 HasPerformedLongPress
2、ACTION_MOVE
主要就是检测用户是否划出控件,如果划出了:
115ms内,直接移除误触和长按检测;
115ms后,则将标志中的PRESSED去除;
3、ACTION_UP
1、如果115ms内,此时标志为PREPRESSED,则清除状态同时往下分发;
2、如果是115ms-500ms间,即长按还未发生,则首先移除长按检测,执行onClick回调;
3、如果是500ms以后,如果LongClickListener消耗事件,则点击事件OnClick事件无法触发;否则点击事件OnClick事件依然可以触发;
4、最后执行mUnsetPressedState.run(),将setPressed传递下去,然后将PRESSED标识去除;
网友评论