Question

I am trying to catch double-tap events using OnTouchListener. I figure I would set a long for motionEvent.ACTION_DOWN, and a different long for a second motionEvent.ACTION_DOWN and measure the time between the two of them and then do something with it. However, I am having a hard time figuring out exactly how to approach this. I am using switch cases to pick up multitouch events, so I'd rather not try and retool this all to implement GestureDetector (and unfortunately it is impossible to implement both ontouchlistener and Gesturedetector simultaneously). Any ideas would help greatly:

i.setOnTouchListener(new OnTouchListener() {

        public boolean onTouch(View v, MotionEvent event) {


                  ImageView i = (ImageView) v;

                  switch (event.getAction() & MotionEvent.ACTION_MASK) {


                  case MotionEvent.ACTION_DOWN:
                      long firstTouch = System.currentTimeMillis();
                     ///how to grab the second action_down????

                     break;
Was it helpful?

Solution

I addressed this problem earlier. It involves using a Handler to wait a certain amount of time to wait for the second click: How can I create a Single Click Event and Double Click Event when the Menu Button is pressed?

OTHER TIPS

In your class definition:

public class main_activity extends Activity
{
    //variable for counting two successive up-down events
   int clickCount = 0;
    //variable for storing the time of first click
   long startTime;
    //variable for calculating the total time
   long duration;
    //constant for defining the time duration between the click that can be considered as double-tap
   static final int MAX_DURATION = 500;
}

Then in your class body:

OnTouchListener MyOnTouchListener = new OnTouchListener()
{
    @Override
    public boolean onTouch (View v, MotionEvent event)
    {
        switch(event.getAction() & MotionEvent.ACTION_MASK)
        {
        case MotionEvent.ACTION_DOWN:
            startTime = System.currentTimeMillis();
            clickCount++;
            break;
        case MotionEvent.ACTION_UP:
            long time = System.currentTimeMillis() - startTime;
            duration=  duration + time;
            if(clickCount == 2)
            {
                if(duration<= MAX_DURATION)
                {
                    Toast.makeText(captureActivity.this, "double tap",Toast.LENGTH_LONG).show();
                }
                clickCount = 0;
                duration = 0;
                break;             
            }
        }
    return true;    
    }
}

This was adapted from an answer in: DoubleTap in android by https://stackoverflow.com/users/1395802/karn

With the helper class SimpleGestureListener that implements the GestureListener and OnDoubleTapListener you dont need much to do.

yourView.setOnTouchListener(new OnTouchListener() {
private GestureDetector gestureDetector = new GestureDetector(Test.this, new GestureDetector.SimpleOnGestureListener() {
    @Override
    public boolean onDoubleTap(MotionEvent e) {
        Log.d("TEST", "onDoubleTap");
        return super.onDoubleTap(e);
    }
    ... // implement here other callback methods like onFling, onScroll as necessary
});

@Override
public boolean onTouch(View v, MotionEvent event) {
    Log.d("TEST", "Raw event: " + event.getAction() + ", (" + event.getRawX() + ", " + event.getRawY() + ")");
    gestureDetector.onTouchEvent(event);
    return true;
}});

That's much easyer:

//variable for storing the time of first click
long startTime;
//constant for defining the time duration between the click that can be considered as double-tap
static final int MAX_DURATION = 200;

    if (event.getAction() == MotionEvent.ACTION_UP) {

        startTime = System.currentTimeMillis();             
    }
    else if (event.getAction() == MotionEvent.ACTION_DOWN) {

        if(System.currentTimeMillis() - startTime <= MAX_DURATION)
        {
            //DOUBLE TAP
        }       
    }

Here is my solution.

It was important for me to have a fast and clear separation of 'single tap' and 'double tap'. I tried GestureDetector first but had very bad results. Maybe a result of my nested use of scrollviews - who knows...

I focus on MotionEvent.ACTION_UP and the ID of the tapped element. To keep the first tap alive I use a Handler sending a delayed message (350ms) so the user has some time to place its second tap on the ImageView. If the user placed a second tap on an element with the identical id I take this as double tap, remove the delayed message and rund my custom code for 'double tap'. If the user placed a tap on an element with a different ID I take this as new tap and create another Handler for it.

Class global variables

private int tappedItemId = -1;
Handler myTapHandler;
final Context ctx = this;

Code example

ImageView iv = new ImageView(getApplicationContext());
//[...]
iv.setId(i*1000+n);
iv.setOnTouchListener(new View.OnTouchListener() {

@Override
public boolean onTouch(View v, MotionEvent event) {

   switch (event.getAction()) {

      case MotionEvent.ACTION_UP: {

         //active 'tap handler' for current id?
         if(myTapHandler != null && myTapHandler.hasMessages(v.getId())) {

            // clean up (to avoid single tap msg to be send and handled)
            myTapHandler.removeMessages(tappedItemId);
            tappedItemId = -1;

            //run 'double tap' custom code
            Toast.makeText(ScrollView.this, "double tap on "+v.getId(), Toast.LENGTH_SHORT).show();

            return true;
         } else {
            tappedItemId = v.getId();
            myTapHandler = new Handler(){
               public void handleMessage(Message msg){
                  Toast.makeText(ctx, "single tap on "+ tappedItemId + " msg 'what': " + msg.what, Toast.LENGTH_SHORT).show();
               }
            };

            Message msg = Message.obtain();
            msg.what = tappedItemId;
            msg.obj = new Runnable() {
               public void run() {
                  //clean up
                  tappedItemId = -1;
               }
            };
            myTouchHandler.sendMessageDelayed(msg, 350); //350ms delay (= time to tap twice on the same element)
         }
         break;
      }
   }

   return true;
 }
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top