在遇到的坑以前咱們先了解 Android onTouchEvent, onClick及onLongClick的調用機制 1. onTouchEvent:java
onTouchEvent中要處理的最經常使用的3個事件就是:ACTION_DOWN(按下)、ACTION_MOVE(移動)、ACTION_UP(擡起)。
複製代碼
2. onClick、onLongClick與onTouchEventgit
在Android中,onClick、onLongClick的觸發是和ACTION_DOWN及ACTION_UP相關的,在時序上,若是咱們在一個View中同時覆寫了onClick、onLongClick及onTouchEvent的話,onTouchEvent是最早捕捉到ACTION_DOWN和ACTION_UP事件的,其次纔可能觸發onClick或者onLongClick。主要的邏輯在View.java中的onTouchEvent方法中實現的,主要的操做是在View.onTucchEvent下的:
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;
if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {
// take focus if we don't have it already and we should in
// touch mode.
boolean focusTaken = false;
if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
focusTaken = requestFocus();
}
if (prepressed) {
// The button is being released before we actually
// showed it as pressed. Make it show the pressed
// state now (before scheduling the click) to ensure
// the user sees it.
setPressed(true, x, y);
}
if (!mHasPerformedLongPress) {
// This is a tap, so remove the longpress check
removeLongPressCallback();
// Only perform take click actions if we were in the pressed state
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)) {
performClick();
}
}
}
if (mUnsetPressedState == null) {
mUnsetPressedState = new UnsetPressedState();
}
if (prepressed) {
postDelayed(mUnsetPressedState,
ViewConfiguration.getPressedStateDuration());
} else if (!post(mUnsetPressedState)) {
// If the post failed, unpress right now
mUnsetPressedState.run();
}
removeTapCallback();
}
break;
case MotionEvent.ACTION_DOWN:
mHasPerformedLongPress = false;
if (performButtonActionOnTouchDown(event)) {
break;
}
// Walk up the hierarchy to determine if we're inside a scrolling container.
boolean isInScrollingContainer = isInScrollingContainer();
// For views inside a scrolling container, delay the pressed feedback for
// a short period in case this is a scroll.
if (isInScrollingContainer) {
mPrivateFlags |= PFLAG_PREPRESSED;
if (mPendingCheckForTap == null) {
mPendingCheckForTap = new CheckForTap();
}
mPendingCheckForTap.x = event.getX();
mPendingCheckForTap.y = event.getY();
postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
} else {
// Not inside a scrolling container, so show the feedback right away
setPressed(true, x, y);
checkForLongClick(0);
}
break;
case MotionEvent.ACTION_CANCEL:
setPressed(false);
removeTapCallback();
removeLongPressCallback();
break;
case MotionEvent.ACTION_MOVE:
drawableHotspotChanged(x, y);
// Be lenient about moving outside of buttons
if (!pointInView(x, y, mTouchSlop)) {
// Outside button
removeTapCallback();
if ((mPrivateFlags & PFLAG_PRESSED) != 0) {
// Remove any future long press/tap checks
removeLongPressCallback();
setPressed(false);
}
}
break;
複製代碼
能夠看到,Click的觸發是在系統捕捉到ACTION_UP後發生並由performClick()執行的;LongClick的觸發則是從ACTION_DOWN開始,由checkForLongClick()方法完成的; 他們執行Touch事件的的順序 ACTION_DOWN -> ACTION_UP -> OnClick/OnLongClick。github
首先,該View會先響應ACTION_DOWN事件,並返回一個boolean值,這裏有兩種判斷: 1. 返回true,表示該View接受此按下動做,就是說這個點擊動做的按下操做被停止,而後就是響應ACTION_UP事件。點擊動做的按下操做被ACTION_DOWN接受以後就結束了,因此以後的OnClick/OnLongClick事件就不會響應了。 2. 返回false,表示該View不接受此按下動做,響應完以後,按下操做繼續往下發,以後是響應ACTION_UP事件,這裏又有一個判斷:ide
若是ACTION_UP事件返回true,表示ACTION_UP接受鬆開操做,鬆開操做停止;View會一直處於按下狀態,以後View便會響應OnLongClick事件。
若是ACTION_UP事件返回false,表示ACTION_UP不接收鬆開操做,鬆開操做繼續下發;由於按下與鬆開操做都沒有被停止,因此以後View就會響應OnClick事件。
複製代碼
下面就是我在魅族中踩的坑了:post
手機在EditText長按進行粘貼,會觸發OnLongClick 的事件,可是我在魅族的手機EditText長按進行粘貼,若是作了onTouchEvent監聽,死活的都不會觸發OnLongClick 的事件,不夠onTouchEvent返回的是true仍是false 都白費,固然也不會進行粘貼;其餘的手機都是按照正常的節奏來,就只有魅族! 找到問題了如今就是怎麼去解決問題,這裏我用到onTouchEvent 主要監聽的是ACTION_MOVE 的處理,既然onTuchEvent不行就只有用其方式來監聽滑動了,用到的是GestureDetector.SimpleOnGestureListener 進行監聽的 :this
public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener {
// --------------OnGestureListener的接口有這幾個----------------
// 擡起,手指離開觸摸屏時觸發(長按、滾動、滑動時,不會觸發這個手勢)
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
// 長按,觸摸屏按下後既不擡起也不移動,過一段時間後觸發
public void onLongPress(MotionEvent e) {
}
// 滾動,觸摸屏按下後移動
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
return false;
}
// 滑動,觸摸屏按下後快速移動並擡起,會先觸發滾動手勢,跟着觸發一個滑動手勢
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
return false;
}
// 短按,觸摸屏按下後片刻後擡起,會觸發這個手勢,若是迅速擡起則不會
public void onShowPress(MotionEvent e) {
}
// 單擊,觸摸屏按下時馬上觸發
public boolean onDown(MotionEvent e) {
return false;
}
//------------------------OnDoubleTapListener的接口有這幾個-----------
// 雙擊,手指在觸摸屏上迅速點擊第二下時觸發
public boolean onDoubleTap(MotionEvent e) {
return false;
}
// 雙擊的按下跟擡起各觸發一次
public boolean onDoubleTapEvent(MotionEvent e) {
return false;
}
// 單擊確認,即很快的按下並擡起,但並不連續點擊第二下
public boolean onSingleTapConfirmed(MotionEvent e) {
return false;
}
}
複製代碼
因而我重寫個人EditText 繼承EditText:spa
public class MyEditText extends EditText {
private GestureDetector mGestureDetector;
private SimpleOnGestureListener simpleOnGestureListener;
private Context context;
public MyEditText(Context context) {
super(context);
this.context = context;
setLongClickable(true);
}
public void setMyGestureListener(SimpleOnGestureListener simpleOnGestureListener) {
this.simpleOnGestureListener = simpleOnGestureListener;
setGestureDetector();
}
public MyEditText(Context context, AttributeSet attrs) {
super(context, attrs);
setLongClickable(true);
this.context = context;
}
private void setGestureDetector() {
mGestureDetector = new GestureDetector(context, simpleOnGestureListener);
this.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
return mGestureDetector.onTouchEvent(event);
}
});
}
複製代碼
} 注意:code
1.這裏必定要記得設置longClickable爲true, 不然手勢識別沒法正確工做,只會返回Down, Show, Long三種手勢
2. 必須在View的onTouchListener中調用手勢識別,而不能像Activity同樣重載onTouchEvent,不然一樣手勢識別沒法正確工做
複製代碼
最後這樣就ok了:orm
mTvEditContent.setMyGestureListener(new SimpleOnGestureListener() {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
// 處理我想作的
return super.onScroll(e1, e2, distanceX, distanceY);
}
});
複製代碼