Android View的onTouchEvent和OnTouch區(qū)別
1.通過重寫onTouchEvent方法來處理諸如MotionEvent.ACTION_DOWN、MotionEvent.ACTION_MOVE/MotionEvent.ACTION_UP的消息:
public class MyTextView extends TextView{
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean value = super.onTouchEvent(event);
System.out.println("super.onTouchEvent: " + value+ " event: " + event.getAction());
return value;
}
}
2.通過實現(xiàn)OnTouchListener的接口,實現(xiàn)onTouch回調(diào):
class MyTouchListener implements View.OnTouchListener{
@Override
public boolean onTouch(View v, MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
return true; //這里返回false的話 無法響應(yīng)MOVE和UP。
}
}
我在之前做的播放器的手勢控制音量、亮度和快進(jìn)回退就是通過這個來控制的,簡單粗暴。
3.倆者區(qū)別:
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)) {
return true;
}
if(onTouchEvent(event)){
return true;
}
}
... ...
return false;
}
onTouchListener的接口的優(yōu)先級是要高于onTouchEvent的,假若onTouchListener中的onTouch方法返回true,表示此次事件已經(jīng)被消費了,那onTouchEvent是接收不到消息的。
onTouchListener的onTouch方法優(yōu)先級比onTouchEvent高,會先觸發(fā)。
假如onTouch方法返回false會接著觸發(fā)onTouchEvent,反之onTouchEvent方法不會被調(diào)用。
類似onclick的事件是基于onTouchEvent實現(xiàn),在onTouch中,如果返回false,則可以響應(yīng)到onTouchEvent,但是無法響應(yīng)到onTouch手勢中的move和up事件。
該小結(jié)參考:http://blog.csdn.net/huiguixian/article/details/22193977
GestureDetector類及其用法
View類有個View.OnTouchListener內(nèi)部接口,通過重寫他的onTouch(View v, MotionEvent event)方法,我們可以處理一些touch事件,但是這個方法太過簡單,如果需要處理一些復(fù)雜的手勢,用這個接口就會很麻煩(因為我們要自己根據(jù)用戶觸摸的軌跡去判斷是什么手勢)。
@Override
public boolean onTouch(View v, MotionEvent event) {
return mGestureDetector.onTouchEvent(event);
}
GestureDetector這個類對外提供了兩個接口:OnGestureListener,OnDoubleTapListener(雙擊),還有一個內(nèi)部類SimpleOnGestureListener。
使用方法
- 實現(xiàn)內(nèi)部方法
- 內(nèi)部類
class MyGestureListener implements GestureDetector.OnGestureListener {
@Override
public boolean onDown(MotionEvent e) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return false;
}
}
- 匿名內(nèi)部類
mGestureDetector = new GestureDetector(mContext, new GestureDetector.OnGestureListener() {
@Override
public boolean onDown(MotionEvent e) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return false;
}
});
- 創(chuàng)建GestureDetector實例
過時
public GestureDetector(OnGestureListener listener, Handler handler) {
this(null, listener, handler);
}
過時
public GestureDetector(OnGestureListener listener) {
this(null, listener, null);
}
public GestureDetector(Context context, OnGestureListener listener) {
this(context, listener, null);
}
public GestureDetector(Context context, OnGestureListener listener, Handler handler)
public GestureDetector(Context context, OnGestureListener listener, Handler handler,
boolean unused) {
this(context, listener, handler);
}
匿名內(nèi)部類
mGestureDetector = new GestureDetector(mContext,new MyGestureListener());
- 實現(xiàn)View.OnTouchListener接口,重寫OnTouch()方法
參照上一段
- 在onTouch()方法中攔截事件處理,將控制權(quán)交給GestureDector。
@Override
public boolean onTouch(View v, MotionEvent event) {
return mGestureDetector.onTouchEvent(event);
}
- View.setOnTouchListener()
super.setOnTouchListener(this);
mGestureDetector.setOnDoubleTapListener(new MyGestureListener());
SimpleOnGestureListener
SimpleOnGestureListener是GestureDetector類的一個內(nèi)部類,該類是static class,也就是說它實際上是一個外部類。可以在外部繼承這個類,重寫里面的具體某些手勢處理方法。
class MyOnGestureListener extends SimpleOnGestureListener{
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return super.onFling(e1, e2, velocityX, velocityY);
}
}
android給我們封裝提供了常用的類,比如雙擊監(jiān)聽android給我們提供OnDoubleTapListener,比如滑動或者按下再抬起的操作,這個android也幫我封裝了好了,實現(xiàn)這個接口SimpleOnGestureListener就行,這個SimpleOnGestureListener類是實現(xiàn)了OnGestureListener,由于這個接口方法過多,所以使用了類SimpleOnGestureListener去實現(xiàn)OnGestureListener接口,你想覆蓋什么方法就重寫就行。
該小結(jié)參考:http://blog.csdn.net/hpk1994/article/details/51224228
http://www.cnblogs.com/rayray/p/3422734.html
事件分發(fā)
- dispatchTouchEvent
只要你觸摸到了任何一個控件,就一定會調(diào)用該控件的dispatchTouchEvent方法,該方法在View和ViewGroup中。比如你點擊button就是button->textView->View。
public boolean dispatchTouchEvent(MotionEvent event) {
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}
根據(jù)代碼可以看出,首先判斷dispatchevent中ontouchlistener是否有值而且要判斷該view是否為enable,第三個條件則是onTouch這個回調(diào)的返回值是否為true,也就是說onTouch為true則dispatchevent根據(jù)前兩個條件直接返回true,否則返回false繼續(xù)向下執(zhí)行,也就意味著后面的onTouchEvent和onclick不會執(zhí)行。
為默認(rèn)在onTouchEvent返回true所以不管ontouch返回的是什么,action_move,action_up都會執(zhí)行。而textview中ontouch不會返true則不會執(zhí)行action_move,action_up。
- onInterceptTouchEvent
當(dāng)你點擊一個layout中的button時,首先點擊的而是最外層layout,所以調(diào)用的是最外層viewGroup的dispatchtouchevent。
而在viewgourp的dispatchtouchevent中有onintercepttouchevent方法默認(rèn)為false,如果這個方法返回true則示為事件攔截,則直接執(zhí)行viewgroup的dispatchevent,否則進(jìn)入下層遍歷所有子view,尋找點擊的子view。
如果父view和子view都有事件消耗,則由于事件傳遞優(yōu)先是子view消耗,然后返回true。 - onTouchEvent
onTouchEvent中MotionEvent.ACTION_UP中performclick中實現(xiàn)了onclick,且返回true。
即dispatchEvent->(onInterceptTouchEvent->dispatchEvent->)onTouch->onTouchEvent->onClick
viewGroup沒有onTouchListener,在viewGroup中dispatchEvent中會有調(diào)用view.dispatchEvent,這個代碼同樣在interceptTouchEvent后面。
該小結(jié)參考:http://blog.csdn.net/guolin_blog/article/details/9097463/
http://blog.csdn.net/guolin_blog/article/details/9153747
getX,getRawX,getWidth,getTranslationX
getLeft、getRight、getTop、getButton分別是四個方向距離父view左側(cè)和上側(cè)的距離。
而getX、getRaw是onTouch里面的方法,分別代表的是觸摸點到自身的距離和觸摸點到屏幕的距離,這個很好理解。
getX和getLeft都是獲取View相對父View左側(cè)的坐標(biāo),但是通過屬性動畫可以改變view的屬性,即x和translateX的值,但是left值不變,所以屬性動畫執(zhí)行后的結(jié)果是x = translationX + left。