小案例:分析setOnTouchListener 与setOnClickListener导致的冲突
场景:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener{
Log.d("TAG", "onclick")
}
button.setOnTouchListener { v, event ->
Log.d("TAG", "OnTouch:$v->${event.action}")
true
}
}
}
**setOnTouchListener 返回true时 打印:**
TAG: OnTouch
TAG: OnTouch
**setOnTouchListener 返回false时 打印:**
TAG: OnTouch
TAG: OnTouch
TAG: onclick
可以看到为false时onclick触发了

分析源码:
1. 从view的dispatchTouchEvent中:
if (onFilterTouchEventForSecurity(event)) {
if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
result = true;
}
//noinspection SimplifiableIfStatement
ListenerInfo li = mListenerInfo;
//li setonTouchListener 时已经赋值不会为null
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
//这里就是setonTouchListener的返回结果影响的 返回true 命中整个if,result此时为true
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
//当result为true 第一个条件判断为false 直接不走整个逻辑 此时onTouchEvent 不会触发
if (!result && onTouchEvent(event)) {
result = true;
}
}
- li.mOnTouchListener.onTouch(this, event)该结果影响到了result的值
2. 当result为false时,从View的 onTouchEvent中看 onclick的触发时机:
在 case MotionEvent.ACTION_UP 中:
// Only perform take click actions if we were in the pressed state
...
if (!post(mPerformClick)) {
performClickInternal();
}
}
再看看performClickInternal()
private boolean performClickInternal() {
...
return performClick();
}
performClick() 就是触发onClick的时机:
public boolean performClick() {
...
if (li != null && li.mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
//这里触发了onclick回调
li.mOnClickListener.onClick(this);
result = true;
} else {
result = false;
}
...
return result;
}
网友评论