【问题标题】:How to catch double tap events in Android using OnTouchListener如何使用 OnTouchListener 在 Android 中捕获双击事件
【发布时间】:2020-08-14 17:29:08
【问题描述】:

我正在尝试使用 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;

【问题讨论】:

标签: android ontouchlistener


【解决方案1】:

在你的类定义中:

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 androidhttps://stackoverflow.com/users/1395802/karn中的答案

【讨论】:

    【解决方案2】:

    使用实现 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;
    }});
    

    【讨论】:

    • 很棒的反应。谢谢
    • 最优雅的解决方案。谢谢!
    【解决方案3】:

    这要容易得多:

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        这是我的解决方案。

        对我来说,快速清晰地区分“单击”和“双击”非常重要。 我首先尝试了GestureDetector,但结果非常糟糕。也许是我嵌套使用滚动视图的结果 - 谁知道...

        我关注MotionEvent.ACTION_UP 和被点击元素的ID。为了让第一次点击保持活跃,我使用Handler 发送延迟消息(350 毫秒),以便用户有时间在ImageView 上进行第二次点击。如果用户在具有相同 id 的元素上再次点击,我将其视为双击,删除延迟的消息并运行我的“双击”自定义代码。如果用户点击了具有不同 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;
         }
        });
        

        【讨论】:

          【解决方案6】:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-01-06
            • 2011-07-02
            • 1970-01-01
            相关资源
            最近更新 更多