分析下OnClickListener,OnLongClickListener,OnTouchListener,onTouchEvent这4个方法的调用关系。
源码分析基于Android-23
1.简述方法作用
1.1 OnTouchListener以及 onTouchEvent
都是可以监听Touch事件,区别在于,前者是通过setOnTouchListener的方式来使用,后者是view的方法,重写即可,常用在自定义控件;
1.2 OnClickListener
监听点击事件;
1.3 OnLongClickListener
监听长按事件。
2.OnTouchListener onTouchEvent两者的关系
2.View.dispatchTouchEvent
(1)dispatchTouchEvent,是事件处理的入口;
(2)当设置了setOnTouchListener,那么li.mOnTouchListener就不为空,onTouch方法会被触发并且返回true,那么onTouchEvent就不会被触发;
(3)没有设置setOnTouchListener或者onTouch方法返回false,那么onTouchEvent就不会被触发;
(4)返回true比较消费了事件;
(5)可以看出mOnTouchListener onTouch方法优先级比onTouchEvent高;
public boolean dispatchTouchEvent(MotionEvent event) {
......
if (onFilterTouchEventForSecurity(event)) {
ListenerInfo 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;
}
}
......
return result;
}
3.OnTouchEvent OnClickListener、OnLongClickListener三者的关系
View.onTouchEvent
(1)主要看down、move、up事件的处理;
(2)down事件,如果view被滑动控件包裹,则isInScrollingContainer为true,需要通过延时任务mPendingCheckForTap判断是tap事件还是滑动事件,如果在延时时间100毫秒内没有任何滑动,则发送400毫秒延时任务执行长按,有任何滑动都将移除mPendingCheckForTap;
(3)上述(2)没有包裹在滑动控件中,则触发checkForLongClick发送500毫秒延时任务执行长按;
(4)up事件,如果长按事件没有被触发或者返回false,mHasPerformedLongPress 则为false,将移除长按任务,接着执行performClick,通过从ViewRootImpl得到的handle往主线程队列发送点击任务,等待被执行,由此可见长按事件被消费了,那么点击事件就无法执行;
(5)performClick内部就是触发li.mOnClickListener.onClick,这里就不展开了;
(6)move事件,移除tap任务removeTapCallback,如果发送了延时任务执行长按,也需要移除removeLongPressCallback;
(7)当onTouchEvent被触发,onClick、onLongClick才有可能被执行,如果onLongClick消费了时间,那么onClick将无法执行;
public boolean onTouchEvent(MotionEvent event) {
......
switch (action) {
case MotionEvent.ACTION_UP:
......
if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
removeLongPressCallback();
......
performClick();
}
......
break;
case MotionEvent.ACTION_DOWN:
......
if (isInScrollingContainer) {
if (mPendingCheckForTap == null) {
mPendingCheckForTap = new CheckForTap();
}
postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
} else {
checkForLongClick(0);
}
break;
case MotionEvent.ACTION_CANCEL:
removeTapCallback();
removeLongPressCallback();
......
break;
case MotionEvent.ACTION_MOVE:
......
if (!pointInView(x, y, mTouchSlop)) {
removeTapCallback();
if ((mPrivateFlags & PFLAG_PRESSED) != 0) {
......
removeLongPressCallback();
}
}
break;
}
return true;
}
return false;
}
5.总结
(1) OnTouchListener onTouch优先级比onTouchEvent高;
(2)当onTouchEvent被触发,onClick、onLongClick才有可能被执行,
(3)当onLongClick消费了事件,那么onClick将无法执行;
(4)点击事件实现,在up事件时,利用ViewRootImpl构建的handler,往主线程MessageQueue发一个runnable点击任务,等待被分发执行;
(5) 长按事件实现,发送100毫秒延时任务判断是tap还是滑动,如果是tap,则再发送400毫秒延时任务执行长按;
有分析不对的地方请指出,互相学习,谢谢哦!
网友评论