近日連續(xù)看了兩篇講觸摸事件的,心里不禁產(chǎn)生了一個(gè)疑問坛吁,故這篇文章也是因?yàn)檫@個(gè)疑問而寫的盏筐。這個(gè)疑問就是:“為什么會(huì)View類里面會(huì)同時(shí)有onTouch和onTouchEvent兩個(gè)觸摸相關(guān)的方法?”如果你心里已經(jīng)有答案了,這篇文章可跳過洒沦,如果有跟我一樣懵逼的,不妨你們也仔細(xì)回憶下到底為什么价淌?
有了這個(gè)疑問在申眼,我們的目的性就很明確了。還是先來看看它們?cè)诖a中的具體用法吧蝉衣。
//...
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;
}
//...
系統(tǒng)先進(jìn)行mOnTouchListener及onTouch返回值等相關(guān)條件的判斷括尸,不滿足的話再執(zhí)行onTouchEvent。病毡,兩個(gè)都是觸摸相關(guān)的濒翻,不同的是onTouch方法比onTouchEvent方法多接收了一個(gè)參數(shù)。這又是為何啦膜?
我們繼續(xù)看系統(tǒng)關(guān)于onTouch方法的說明:
/**
* Interface definition for a callback to be invoked when a touch event is
* dispatched to this view. The callback will be invoked before the touch
* event is given to the view.
*/
public interface OnTouchListener {
/**
* Called when a touch event is dispatched to a view. This allows listeners to
* get a chance to respond before the target view.
*
* @param v The view the touch event has been dispatched to.
* @param event The MotionEvent object containing full information about
* the event.
* @return True if the listener has consumed the event, false otherwise.
*/
boolean onTouch(View v, MotionEvent event);
}
注釋說OnTouchListener是一個(gè)接口回調(diào)有送,當(dāng)觸摸事件分發(fā)到該View時(shí)它會(huì)被調(diào)用。
emm.從字面意思好像明白點(diǎn)什么
接著看onTouchEvent的:
/**
* Implement this method to handle touch screen motion events.
* <p>
* If this method is used to detect click actions, it is recommended that
* the actions be performed by implementing and calling
* {@link #performClick()}. This will ensure consistent system behavior,
* including:
* <ul>
* <li>obeying click sound preferences
* <li>dispatching OnClickListener calls
* <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when
* accessibility features are enabled
* </ul>
*
* @param event The motion event.
* @return True if the event was handled, false otherwise.
*/
public boolean onTouchEvent(MotionEvent event) {
//...
}
實(shí)現(xiàn)這個(gè)用法用來處理觸摸屏幕的一些事件動(dòng)作雀摘,如果這個(gè)方法用來檢測(cè)點(diǎn)擊動(dòng)作,通常建議該動(dòng)作由實(shí)現(xiàn)performClick方法發(fā)出八拱。
從以上兩段注釋來看阵赠,姑且可以給個(gè)總結(jié):
onTouch方法用來在進(jìn)行真正的觸摸事件處理之前可以做些額外的事情涯塔。
好像有點(diǎn)攔截的味道。那到底攔截觸摸事件干嘛呢清蚀?觸摸事件之前還有什么要優(yōu)先處理的呢匕荸?
再讀遍上面的總結(jié),其實(shí)核心在于 “攔截觸摸事件處理”枷邪。那觸摸事件到底在處理什么呢每聪,我們?cè)僮屑?xì)看看onTouchEvent的源碼:
public boolean onTouchEvent(MotionEvent event) {
final float x = event.getX();
final float y = event.getY();
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 ((viewFlags & ENABLED_MASK) == DISABLED) {
if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
setPressed(false);
}
mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
// A disabled view that is clickable still consumes the touch
// events, it just doesn't respond to them.
return clickable;
}
//...
方法開始就進(jìn)行了clickable變量的判斷,如果是DISABLED的直接后面方法不執(zhí)行了齿风,這個(gè)變量作用可太大了药薯,再看其名字,有click字樣救斑,莫非跟點(diǎn)擊事件有關(guān)童本,繼續(xù)往后看:
if (!focusTaken) {
// Use a Runnable and post this rather than calling
// performClick directly. This lets other visual state
// of the view update before click actions start.
if (mPerformClick == null) {
mPerformClick = new PerformClick();
}
if (!post(mPerformClick)) {
performClickInternal();
}
}
果然看到了熟悉的performClick.里面就是很普通的click回調(diào)了:
public boolean performClick() {
//...
final ListenerInfo li = mListenerInfo;
if (li != null && li.mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
li.mOnClickListener.onClick(this);
//...
}
結(jié)論:
所以onTouchEvent的重要性不言而喻了脸候,那點(diǎn)擊觸摸都有它處理了穷娱,onTouch又有什么用呢?回憶上面的代碼运沦,點(diǎn)擊事件嵌入在onTouchEvent里泵额,比如我們有個(gè)控件只想要觸摸監(jiān)聽,不需要點(diǎn)擊事件携添,那單純的onTouchEvent方法顯然沒法滿足我們的需求嫁盲,此時(shí)onTouch方法就派上用場(chǎng)了。在它里面處理烈掠,結(jié)果返回true羞秤,直接繞過了onTouchEvent里眾多復(fù)雜流程,豈不快哉左敌!