How to catch double tap events in Android using OnTouchListener

后端 未结 6 1720
孤独总比滥情好
孤独总比滥情好 2020-12-31 08:45

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_D

相关标签:
6条回答
  • 2020-12-31 09:08

    Another approach that supports both single click and double clicks using Kotlin Coroutine:

    var lastDown = 0L
    var clickCount = 0
    
    view.setOnTouchListener {v, event ->
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                val downTime = System.currentTimeMillis()
                clickCount++
                if (lastDown > 0 && downTime - lastDown < 300 && clickCount == 2) {
                    //double clicks happens here
                    clickCount = 0
                }
                lastDown = downTime
            }
            MotionEvent.ACTION_UP -> {
                CoroutineScope(Dispatchers.IO).launch {
                    //in case clickCount goes beyond than 1, here set it to 1
                    val upTime = System.currentTimeMillis()
                    if (upTime - lastDown <= 300 && clickCount > 0) {
                        clickCount = 1
                    }
                    delay(300)
                    if (System.currentTimeMillis() - lastDown > 300 && clickCount == 1) {
                        withContext(Dispatchers.Main) {
                            //single click happens here
                        }
                        clickCount = 0
                    }
                }
            }
        }
        true
    }
    
    0 讨论(0)
  • 2020-12-31 09:09

    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;
    }});
    
    0 讨论(0)
  • 2020-12-31 09:10

    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
            }       
        }
    
    0 讨论(0)
  • 2020-12-31 09:27

    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?

    0 讨论(0)
  • 2020-12-31 09:34

    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

    0 讨论(0)
  • 2020-12-31 09:35

    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;
     }
    });
    
    0 讨论(0)
提交回复
热议问题