2013-08-01 119 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; 
           } 
          });