2013-08-01 43 views
10

我需要在自定義視圖的ontouch方法中使用單點觸摸檢測。我試圖在ACTION-DOWN和ACTION-UP以及ACTION-UP中得到x和y值,我給出了一個條件,如果ACTIONDOWN和ACTION-UP中X和Y的值相等,則將其作爲單個tap 。單點觸摸檢測在視圖的Ontouch方法中

我的代碼如下

@Override 
public boolean onTouchEvent(MotionEvent ev) { 
    if (!mSupportsZoom && !mSupportsPan) return false; 

    mScaleDetector.onTouchEvent(ev); 

    final int action = ev.getAction(); 
    switch (action & MotionEvent.ACTION_MASK) { 
    case MotionEvent.ACTION_DOWN: { 
     final float x = ev.getX(); 
     final float y = ev.getY(); 

     mLastTouchX = x; //here i get x and y values in action down 
     mLastTouchY = y; 
     mActivePointerId = ev.getPointerId(0); 

     break; 
    } 

    case MotionEvent.ACTION_MOVE: { 
     final int pointerIndex = ev.findPointerIndex(mActivePointerId); 
     final float x = ev.getX(pointerIndex); 
     final float y = ev.getY(pointerIndex); 

     if (mSupportsPan && !mScaleDetector.isInProgress()) { 
      final float dx = x - mLastTouchX; 
      final float dy = y - mLastTouchY; 

      mPosX += dx; 
      mPosY += dy; 
      //mFocusX = mPosX; 
      //mFocusY = mPosY; 

      invalidate(); 
     } 

     mLastTouchX = x; 
     mLastTouchY = y; 

     break; 
    } 

    case MotionEvent.ACTION_UP: { 

     final float x = ev.getX(); 
     final float y = ev.getY(); 

     touchupX=x; //here is get x and y values at action up 
     touchupY=y; 

     if(mLastTouchX == touchupX && mLastTouchY == touchupY){ //my condition if both the x and y values are same . 

      PinchZoomPanActivity2.tapped1(this.getContext(), 100); //my method if the singletap is detected 

     } 
     else{ 

     } 

     mActivePointerId = INVALID_POINTER_ID; 

     break; 
    } 

    case MotionEvent.ACTION_CANCEL: { 
     mActivePointerId = INVALID_POINTER_ID; 
     break; 
    } 

    case MotionEvent.ACTION_POINTER_UP: { 
     final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) 
       >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; 
     final int pointerId = ev.getPointerId(pointerIndex); 
     if (pointerId == mActivePointerId) { 

      final int newPointerIndex = pointerIndex == 0 ? 1 : 0; 
      mLastTouchX = ev.getX(newPointerIndex); 
      mLastTouchY = ev.getY(newPointerIndex); 
      mActivePointerId = ev.getPointerId(newPointerIndex); 
     } 
     break; 
    } 
    } 

    return true; 
} 

,但我不能把它做完。我的意思是在我的方法被調用的每一個動作。即使actionup和actiondown的x和y值不相同。而且我認爲我們還需要在屏幕上用手指觸摸時將一些範圍添加到singletap。任何人都可以給我一些建議嗎?

+0

它永遠不會在完全相同的地方 - 你的手指總是會稍微移動。使用範圍檢查 - 確保abs(upLoc-downLoc)<5 –

+0

我需要使用範圍檢查,但我不明白你的「abs(upLoc-downLoc)<5」。 –

+0

abs =絕對值。這意味着如果位置變化小於5個像素。 –

回答

6

我最近也遇到了同樣的問題,最後不得不實施去抖動來使它工作。這不是理想的,但它是相當可靠的,直到我能找到更好的東西。

View.onClickListener對我來說更加可靠,但不幸的是我需要從OnTouchListener中獲取MotionEvent。

編輯:刪除多餘的代碼,會導致它失敗在這裏

class CustomView extends View { 

    private static long mDeBounce = 0; 

    static OnTouchListener listenerMotionEvent = new OnTouchListener() { 
     @Override 
     public boolean onTouch(View view, MotionEvent motionEvent) { 
      if (Math.abs(mDeBounce - motionEvent.getEventTime()) < 250) { 
       //Ignore if it's been less then 250ms since 
       //the item was last clicked 
       return true; 
      } 

      int intCurrentY = Math.round(motionEvent.getY()); 
      int intCurrentX = Math.round(motionEvent.getX()); 
      int intStartY = motionEvent.getHistorySize() > 0 ? Math.round(motionEvent.getHistoricalY(0)) : intCurrentY; 
      int intStartX = motionEvent.getHistorySize() > 0 ? Math.round(motionEvent.getHistoricalX(0)) : intCurrentX; 

      if ((motionEvent.getAction() == MotionEvent.ACTION_UP) && (Math.abs(intCurrentX - intStartX) < 3) && (Math.abs(intCurrentY - intStartY) < 3)) { 
       if (mDeBounce > motionEvent.getDownTime()) { 
        //Still got occasional duplicates without this 
        return true; 
       } 

       //Handle the click 

       mDeBounce = motionEvent.getEventTime(); 
       return true; 
      } 
      return false; 
     } 
    }; 
} 
+1

非常感謝。根據我的說法,這個works.best功能可以在ontouch中雙擊。多點觸控時可能會發現一些故障,但這是最好的。 –

+0

不適用於我,這甚至覆蓋我的雙擊方法 – Casper

0

認爲你不需要使用「相等」的操作符。代替它使用近似值

case MotionEvent.ACTION_DOWN: { 
    final int CONST = 5; 
    final float x = ev.getX(); 
    final float y = ev.getY(); 

    mLastTouchXMax = x+CONST; //here i get x and y values in action down 
    mLastTouchXMin = x-CONST; 
    mLastTouchYMax = y+CONST; 
    mLastTouchYMin = y-CONST; 
    mActivePointerId = ev.getPointerId(0); 

    break; 
} 

並在ACTION_UP中檢查間隔之間的X和Y值。

+0

我不明白在行動Up.i需要做什麼。我需要檢查在行動up x和y值是否在行動下的四個值down.but我將如何做到這一點。幫助我,謝謝你。 –

4

添加GestureDetector.SimpleOnGestureListener用於查看和使用方法onSingleTapConfirmed在這個

只有當Android操作系統已確認觸摸特定是單擊並且不是雙擊時纔會調用此方法。

你可以谷歌的Android例子。

+0

是的,我試過這個..但我有這個singletap或doubletap一些其他問題。不管怎麼說,多謝拉。 –

+0

onSingleTapConfirmed將被調用,只有水龍頭是單一的。這裏沒有混淆。 查看方法名稱本身說它看到onSingleTapConfirmed。 我不知道你指的是什麼其他問題,我認爲你沒有正確處理返回值。覈實! – Charan

+0

我的問題不是與手勢監聽器,而是與我的應用程序。我的應用程序包含多點觸控平移的自定義視圖,並放大ontouch,這不利於手勢監聽器。 –

29

檢測單和槍王android中我使用下面的方法:

class GestureTap extends GestureDetector.SimpleOnGestureListener { 
    @Override 
    public boolean onDoubleTap(MotionEvent e) { 
     Log.i("onDoubleTap :", "" + e.getAction()); 
     return true; 
    } 

    @Override 
    public boolean onSingleTapConfirmed(MotionEvent e) { 
     Log.i("onSingleTap :", "" + e.getAction()); 
     return true; 
    } 
} 

用它GestureDetector的構造函數:

detector = new GestureDetector(this, new GestureTap()); 

而且在onTouch監聽器添加以下代碼

@Override 
public boolean onTouchEvent(MotionEvent event) { 

    detector.onTouchEvent(event); 

    return true; 
} 
+0

+1先生謝謝你挽救我的工作和生活。你是天使。還要補充一點,以下是您可以覆蓋的更多支持手勢的參考: https://developer.android.com/training/gestures/detector.html#detect。看看'檢測手勢'部分。 –

2

有一個更簡單和直接的方法。 使用MotionEvent.ACTION_DOWN & & MotionEvent.ACTION_UP和計時事件之間的差異。

完整的代碼可以在這裏找到。https://stackoverflow.com/a/15799372/3659481

setOnTouchListener(new OnTouchListener() { 
private static final int MAX_CLICK_DURATION = 200; 
private long startClickTime; 

@Override 
public boolean onTouch(View v, MotionEvent event) { 
    switch (event.getAction()) { 
     case MotionEvent.ACTION_DOWN: { 
      startClickTime = Calendar.getInstance().getTimeInMillis(); 
      break; 
     } 
     case MotionEvent.ACTION_UP: { 
      long clickDuration = Calendar.getInstance().getTimeInMillis() - startClickTime; 
      if(clickDuration < MAX_CLICK_DURATION) { 
       //click event has occurred 
      } 
     } 
    } 
    return true; 
} 

}

7

增加對完整性的考慮答案,如果任何人達到這裏:

可以使用GestureDetectorOnTouchListener

final GestureDetector gestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() { 
     @Override 
     public boolean onSingleTapConfirmed(MotionEvent e) { 
     //do something 
      return true; 
     } 

     @Override 
     public void onLongPress(MotionEvent e) { 
      super.onLongPress(e); 
     } 

     @Override 
     public boolean onDoubleTap(MotionEvent e) { 
      return super.onDoubleTap(e); 
     } 
    }); 

viewToTouch.setOnTouchListener(new View.OnTouchListener() { 
     @Override 
     public boolean onTouch(View v, MotionEvent event) { 

      return gestureDetector.onTouchEvent(event); 
     } 
    }); 
0
float dX,dY,x,y;  
tv.setOnTouchListener(new View.OnTouchListener() { 
           @Override 
           public boolean onTouch(View view, MotionEvent event) { 
            switch (event.getAction()) { 
             case MotionEvent.ACTION_UP:  //Event for On Click 
              if(x==view.getX() && y==view.getY()){ 
               Toast.makeText(getApplicationContext(),"TextView Clicked",Toast.LENGTH_LONG).show(); 
              } 
              break; 
             case MotionEvent.ACTION_DOWN: 
              x=view.getX(); 
              y=view.getY(); 
              dX = view.getX() - event.getRawX(); 
              dY = view.getY() - event.getRawY(); 
              break; 

             case MotionEvent.ACTION_MOVE: 
              view.animate() 
                .x(event.getRawX() + dX) 
                .y(event.getRawY() + dY) 
                .setDuration(0) 
                .start(); 
              break; 
             default: 
              return false; 
            } 
            return true; 
           } 
          });