原始博客有对源码的分析:http://blog.csdn.net/lmj623565791/article/details/39102591
结论:1.view事件的分发流程:
dispatchTouchEvent -> setOnTouchListener(onTouch) -> onTouchEvent。
View拦截到事件之后首先在dispatchTouchEvent中判断是否设置了监听,如果没有就调用onTouchEvent,onTouchEvent默认返回的是true消费事件,如果返回false最后将有ParentView处理事件。
如果在setOnTouchListenner中返回时true说明消费了这个事件,那么后续的onTouchEvent将不会执行。
2.onTouchEvent中的move down up
a、首先设置标志为PREPRESSED,设置mHasPerformedLongPress=false ;然后发出一个115ms后的mPendingCheckForTap;
b、如果115ms内没有触发UP,则将标志置为PRESSED,清除PREPRESSED标志,同时发出一个延时为500-115ms的,检测长按任务消息;
c、如果500ms内(从DOWN触发开始算),则会触发LongClickListener:
此时如果LongClickListener不为null,则会执行回调,同时如果LongClickListener.onClick返回true,才把mHasPerformedLongPress设置为true;否则mHasPerformedLongPress依然为false;
MOVE时:
主要就是检测用户是否划出控件,如果划出了:
115ms内,直接移除mPendingCheckForTap;
115ms后,则将标志中的PRESSED去除,同时移除长按的检查:removeLongPressCallback();
UP时:
a、如果115ms内,触发UP,此时标志为PREPRESSED,则执行UnsetPressedState,setPressed(false);会把setPress转发下去,可以在View中复写dispatchSetPressed方法接收;
b、如果是115ms-500ms间,即长按还未发生,则首先移除长按检测,执行onClick回调;
c、如果是500ms以后,那么有两种情况:
i.设置了onLongClickListener,且onLongClickListener.onClick返回true,则点击事件OnClick事件无法触发;
ii.没有设置onLongClickListener或者onLongClickListener.onClick返回false,则点击事件OnClick事件依然可以触发;
d、最后执行mUnsetPressedState.run(),将setPressed传递下去,然后将PRESSED标识去除;
注意:1.SetonLongClickListener与SetonClickListener是否只能执行一个?不是的在public boolean onLongClick(View v)返回如果是false将会继续执行onCliclk返回true就不会执行。
另外对于onTouchEvent中的move与up如果在setOnTouchEvent中拦截了事件,那么onTouchEvent不会执行后续所有的move click longclick 都不会执行了。