如何使用OnTouchListener捕捉Android中的双击事件

如何使用OnTouchListener捕捉Android中的双击事件,android,ontouchlistener,Android,Ontouchlistener,我正在尝试使用OnTouchListener捕捉双击事件。我想我应该为motionEvent.ACTION\u设置一个long,为第二个motionEvent.ACTION\u设置一个不同的long,然后测量两者之间的时间,然后对其进行处理。然而,我很难弄清楚到底该怎么做。我使用开关盒来拾取多点触控事件,所以我不想尝试重新装备这些来实现GestureDetector(不幸的是,不可能同时实现ontouchlistener和GestureDetector)。任何想法都会大有帮助: i.setOnT

我正在尝试使用OnTouchListener捕捉双击事件。我想我应该为motionEvent.ACTION\u设置一个long,为第二个motionEvent.ACTION\u设置一个不同的long,然后测量两者之间的时间,然后对其进行处理。然而,我很难弄清楚到底该怎么做。我使用开关盒来拾取多点触控事件,所以我不想尝试重新装备这些来实现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;

我早些时候解决了这个问题。它涉及到使用处理程序等待一定时间来等待第二次单击:

在类定义中:

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;    
    }
}
OnTouchListener MyOnTouchListener=新建OnTouchListener()
{
@凌驾
公共布尔onTouch(视图v,运动事件)
{
开关(event.getAction()&MotionEvent.ACTION\u掩码)
{
case MotionEvent.ACTION\u DOWN:
startTime=System.currentTimeMillis();
点击计数++;
打破
case MotionEvent.ACTION\u UP:
长时间=System.currentTimeMillis()-startTime;
持续时间=持续时间+时间;
如果(单击计数=2)
{
如果(持续时间这更容易:

//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
        }       
    }
//用于存储首次单击时间的变量
长启动时间;
//用于定义可被视为双击的两次单击之间的持续时间的常量
静态最终整数最大持续时间=200;
if(event.getAction()==MotionEvent.ACTION\u UP){
startTime=System.currentTimeMillis();
}
else if(event.getAction()==MotionEvent.ACTION\u DOWN){
如果(System.currentTimeMillis()-startTime,这是我的解决方案

对我来说,快速清晰地区分“单点击”和“双点击”是很重要的。 我首先尝试了
手势检测器
,但结果非常糟糕。可能是我嵌套使用ScrollView的结果-谁知道

我主要关注
MotionEvent.ACTION\u UP
和被点击元素的ID。为了保持第一次点击活动,我使用
处理程序发送延迟消息(350ms)因此,用户有一些时间在
ImageView
上进行第二次点击。如果用户在具有相同id的元素上进行第二次点击,我将其视为双击,删除延迟消息并运行我的自定义代码进行“双击”。如果用户在具有不同id的元素上进行了点击,我将其视为新点击并创建另一个
处理程序

分类全局变量

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

使用实现GestureListener和OnDoubleTapListener的助手类SimpleGetStureListener,您不需要做很多事情

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

另一种使用Kotlin协同程序同时支持单击和双击的方法:

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
}
var lastDown=0L
var clickCount=0
view.setOnTouchListener{v,事件->
何时(事件、动作){
MotionEvent.ACTION\u向下->{
val停机时间=System.currentTimeMillis()
点击计数++
如果(lastDown>0&&downTime-lastDown<300&&clickCount==2){
//双击在这里发生
单击计数=0
}
lastDown=停机时间
}
MotionEvent.ACTION\u UP->{
协同路由示波器(Dispatchers.IO)。启动{
//如果clickCount超过1,请在此处将其设置为1
val正常运行时间=System.currentTimeMillis()
if(正常运行时间-上次停机0){
单击计数=1
}
延迟(300)
如果(System.currentTimeMillis()-lastDown>300&&clickCount==1){
withContext(Dispatchers.Main){
//这里只需点击一下
}
单击计数=0
}
}
}
}
真的
}

为什么不使用此选项,因为这需要实现gesturedetector,而我无法与OnTouchListener同时实现此选项。此选项可能会有所帮助,尽管事件正在进行中,但仍然是一个gesturedetector事件,响应非常棒。感谢最优雅的解决方案。谢谢!