Android事件分發(fā)
view的事件分發(fā)之onTouch和onClick
項目中我們經(jīng)常會遇到對一個控件重寫兩個方法setOnClickListener和setOnTouchListener來監(jiān)聽這個控件的點擊事件和動作挟阻,但是如果對于一個控件的這兩個方法同時監(jiān)聽甘磨,會怎樣去執(zhí)行呢?
->我們先對默認可以點擊的控件,如Button進行分析枪向。
我們在一個activity中放一個Button控件,然后設置監(jiān)聽
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e(tag, "onClick");
}
});
button.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i(tag, "viewbutton-onTouch-ACTION_DOWN...");
break;
case MotionEvent.ACTION_UP:
Log.i(tag, "viewbutton-onTouch-ACTION_UP...");
break;
default:
break;
}
return false;
}
}
);
點擊此控件的話,是onTouch先執(zhí)行彼硫,然后執(zhí)行onClick,如果onTouch返回true,那么只執(zhí)行onClick吃溅。
我們從dispatchTouchEvent源碼得知
if (onFilterTouchEventForSecurity(event)) {
//noinspection SimplifiableIfStatement
ListenerInfo li = mListenerInfo;
if (li != null &&
// 監(jiān)聽事件不為空
li.mOnTouchListener != null
// enable為true
&& (mViewFlags & ENABLED_MASK) == ENABLED
// 這里會先執(zhí)行
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) {
result = true;
}
}
在我標注的地方會先執(zhí)行溶诞,即 onTouch(this, event),如果返回true的話决侈,就不會執(zhí)行下面的判斷條件很澄,就是不執(zhí)行onTouchEvent(event)。但是為什么不執(zhí)行onClick呢?
我們在查看onTouchEvent(event)的源碼的時候會發(fā)現(xiàn)
if (mPerformClick == null) {
mPerformClick = new PerformClick();
}
if (!post(mPerformClick)) {
performClick();
}
而在performClick()中有:
if (li != null && li.mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
li.mOnClickListener.onClick(this);
result = true;
} else {
result = false;
}
就是執(zhí)行onClick甩苛。所以我們的流程就是
先調(diào)用控件的dispatchTouchEvent(),然后執(zhí)行onTouch(),如果onTouch()返回false的話俏站,執(zhí)行控件的onTouchEvent方法讯蒲,繼而執(zhí)行onClick方法。
->我們現(xiàn)在對默認不可點擊的事件進行分析肄扎,如ImageView:
執(zhí)行順序其實和上面是一樣的墨林,但是在onTouchEvent方法中,有這么一個判斷條件:
if (((viewFlags & CLICKABLE) == CLICKABLE ||
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||
(viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {
先判斷時候可以點擊犯祠,如果不能就不會進入旭等,然后就不會執(zhí)行onClick方法。如果想讓此種view能執(zhí)行點擊事件衡载,可以設置setClickable(true)搔耕;