如何使用OnTouchListener在Android中捕获双击事件

时间:2011-09-06 03:16:31

标签: android ontouchlistener

我正在尝试使用OnTouchListener捕获双击事件。我想我会为motionEvent.ACTION_DOWN设置一个long,为第二个motionEvent.ACTION_DOWN设置一个不同的long,并测量它们之间的时间,然后用它做一些事情。但是,我很难弄清楚如何处理这个问题。我正在使用switch case来获取多点触控事件,所以我宁愿不尝试重新设计这一切以实现GestureDetector(不幸的是,同时实现ontouchlistener和Gesturedetector是不可能的)。任何想法都会有很大帮助:

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;

6 个答案:

答案 0 :(得分:12)

在班级定义中:

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;
}

然后在你的课堂上:

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;    
    }
}

这是根据DoubleTap in android

中的答案改编的:https://stackoverflow.com/users/1395802/karn

答案 1 :(得分:8)

使用实现GestureListener和OnDoubleTapListener的帮助器类SimpleGestureListener,您不需要做太多事情。

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;
}});

答案 2 :(得分:6)

N#39;这么容易:

//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
        }       
    }

答案 3 :(得分:2)

我之前提到了这个问题。它涉及使用Handler等待一段时间等待第二次点击:How can I create a Single Click Event and Double Click Event when the Menu Button is pressed?

答案 4 :(得分:0)

这是我的解决方案。

对我来说,快速清晰地分离“单击”是非常重要的。和&#39;双击&#39;。 我先尝试GestureDetector,但效果非常糟糕。也许是我嵌套使用scrollviews的结果 - 谁知道......

我专注于MotionEvent.ACTION_UP和点击元素的ID。为了保持第一次点击活动,我使用Handler发送延迟消息(350毫秒),以便用户有时间在ImageView上进行第二次点击。如果用户再次点击具有相同ID的元素,我将其作为双击,删除延迟的消息并使用自定义代码来“双击”#39;。如果用户点击了具有不同ID的元素,我将其作为新点按,并为其创建另一个Handler

班级全局变量

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

代码示例

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;
 }
});

答案 5 :(得分:0)

使用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
}