onTouch和onClick
程序中一般会使用onTouch事件和onClick事件来处理用户行为触发的代码
XXX.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.i("ceshi","onTouch");
return false;
}
});
XXX.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i("ceshi","onClick");
}
});
用户点击,首先触发onTouch事件,然后执行onClick事件,但是当onTouch事件返回值设置为true时,事件就被拦截了,onClick事件就不再执行
为什么返回true就不再执行,就需要说到另一个方法dispatchTouchEvent
dispatchTouchEvent
dispatchTouchEvent是用户事件触发的入口,页面控件被用户点击后,系统会触发dispatchTouchEvent方法,该方法大致执行代码如下:
public boolean dispatchTouchEvent(MotionEvent event) {
boolean result = false;
// 如果mOnTouchListener不为空,且控件处于可控状态,就执行onTouch
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
// 如果mOnTouchListener为空,或控件不可控,或onTouch返回false,就执行onTouchEvent
if (!result && onTouchEvent(event)) {
result = true;
}
return result;
}
执行了如下逻辑判断:
1.判断onTouchListener是否不为空,控件是否可控
2.如果都满足,执行onTouchListener的onTouch方法
3.根据onTouch方法的返回值,决定是否执行onTouchEvent方法
4.如果onTouch返回值是false,执行onTouchEvent
综上,onTouch返回false,执行onTouchEvent。onClick在哪呢,就要去onTouchEvent中看看了
onTouchEvent
该方法大致执行代码如下,次要代码已删减:
public boolean onTouchEvent(MotionEvent event) {
final int viewFlags = mViewFlags;
final int action = event.getAction();
final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE
|| (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
|| (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE;
if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
switch (action) {
case MotionEvent.ACTION_UP:
if (!focusTaken) {
if (mPerformClick == null) {
mPerformClick = new PerformClick();
}
if (!post(mPerformClick)) {
performClickInternal();
}
}
break;
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_CANCEL:
break;
case MotionEvent.ACTION_MOVE:
break;
}
return true;
}
return false;
}
可以看到,经过一系列的判断后,最终执行了performClickInternal方法,我们再去performClickInternal方法中看看
private boolean performClickInternal() {
// Must notify autofill manager before performing the click actions to avoid scenarios where
// the app has a click listener that changes the state of views the autofill service might
// be interested on.
notifyAutofillManagerOnClick();
return performClick();
}
可以发现performClickInternal方法中执行了performClick,继续深入
public boolean performClick() {
// We still need to call this method to handle the cases where performClick() was called
// externally, instead of through performClickInternal()
notifyAutofillManagerOnClick();
final boolean result;
final ListenerInfo li = mListenerInfo;
if (li != null && li.mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
li.mOnClickListener.onClick(this);
result = true;
} else {
result = false;
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
notifyEnterOrExitForAutoFillIfNeeded(true);
return result;
}
找到这里,终于发现了OnClickListener.onClick。
总结,整体执行流程如下:
1、用户点击页面控件→执行dispatchTouchEvent
2、dispatchTouchEvent中执行OnTouchListener的onTouch方法
3、如果onTouch返回值为false→执行onTouchEvent
4、执行onTouchEvent中的performClickInternal方法
5、执行performClickInternal中的performClick方法
6、执行performClick中的OnClickListener的onClick方法