【问题标题】:Android : How to implement longpress manually in touch event?Android:如何在触摸事件中手动实现长按?
【发布时间】:2012-04-06 18:21:23
【问题描述】:

短版:我想要一种在 onTouchEvent 上启动基于时间的计数器的方法,并测试在响应之前是否经过了一定的时间,作为手动 LongTouch 检测。

说明: 我有一个自定义的 imageView 可以在两根手指上滑入/滑出屏幕。我想向它添加拖动事件,但这些事件需要比长按更快。我可以通过使用一个计数器来延迟拖动事件,该计数器在每个 onTouchEvent 更新一次并且仅触发拖动,例如 10 次计数,但计数器仅在触摸事件时更新,并且手指必须在移动。

我如何创建一个基于时间的计数器,一个每秒递增 60 次或类似的活动级别字段?

【问题讨论】:

    标签: android timer long-press


    【解决方案1】:

    我不确定你的问题,但似乎你正试图在你的 onTouchListener 中实现一个捕获长点击事件,除非你需要在 ACTION_UP 事件发生之前执行某种逻辑?如果是这样,那与我遇到的问题完全相同。我也尝试过使用 System.nanoTime() 但我发现了一个不那么棘手的方法。您可以使用计时器,您只需将其安排在第一个 ACTION_DOWN 事件上,并在发生任何不利情况时取消它(例如 ACTION_UP 意味着它不是长按,而只是单击,或者 ACTION_MOVE 位移超过一定的门槛)。类似于以下内容:

    layout.seyOnTouchListener(new OnTouchListener(){
        private Timer longpressTimer; //won't depend on a motion event to fire
        private final int longpressTimeDownBegin = 500; //0.5 s
        private Point previousPoint;
    
        switch(event.getAction()){
    
        case MotionEvent.ACTION_DOWN:{
            longPressTimer = new Timer();
            longpressTimer.schedule(new TimerTask(){
                //whatever happens on a longpress
            }, longpressTimeDownBegin);
            return true; //the parent was also handling long clicks
        }
        case MotionEvent.ACTION_MOVE:{
            Point currentPoint = new Point((int)event.getX(), (int)event.getY());
    
            if(previousPoint == null){
                previousPoint = currentPoint;
            }
            int dx = Math.abs(currentPoint.x - previousPoint.x);
            int dy = Math.abs(currentPoint.y - previousPoint.y);
            int s = (int) Math.sqrt(dx*dx + dy*dy);
            boolean isActuallyMoving = s >= minDisToMove; //we're moving
    
            if(isActuallyMoving){ //only restart timer over if we're actually moving (threshold needed because everyone's finger shakes a little)
                cancelLongPress();
                return false; //didn't trigger long press (will be treated as scroll)
            }
            else{ //finger shaking a little, so continue to wait for possible long press
                return true; //still waiting for potential long press
            }
        }
        default:{
            cancelLongPress();
            return false;
        }
        }
    }
    

    【讨论】:

    • 可能差别不大,但作为优化,我建议删除 Math.sqrt() 函数,因为计算数字的平方根往往很慢。只需将 minDisToMove 更改为 minSquareDisToMove,并将距离的平方指定为阈值。另请参阅此answer 作为检测长按的替代方法。
    【解决方案2】:

    只要看看android的源代码就行了。

    在 GestureDetector 中长按会在“按键按下”时启动延迟消息。 当此消息在“key up”之前出现时,它是长按。

    只是一个指向源的链接 http://www.devdaily.com/java/jwarehouse/android/core/java/android/view/GestureDetector.java.shtml

    【讨论】:

    • 谢谢,但我没有使用手势。手动评估触摸事件对于我想要做的事情更加灵活和方便。触摸事件系统提供了除时间之外的极好的信息。因此需要一个简单的时钟来测量触摸事件中的按压。 ;)
    • 当然,不过查看 GestureDetector 的源代码将显示如何解决这个问题。延迟的消息是你的“时钟”
    • 感谢来源。现在看。
    【解决方案3】:

    我解决这个问题的方法是在 Action_Down 发生时将一些布尔值设置为 true。如果 action_up 发生,则将布尔值设置为 false。当 action_down 发生时,还可以将 postDelayed 设置为您想要的任何延迟。在 postdelayed 中,如果您之前设置为 true 的布尔值仍然为 true,则执行您想要的操作。抱歉这么冗长的回答,但我就是这样做的。

    【讨论】:

    • 好的,我明白你在说什么。延迟执行并中断它。我认为这不会起作用,因为我不执行 ActionUp。我有两个动作。 1) 从菜单中拖动图标 2) 两指轻弹菜单开/关屏幕。拖拽的延迟只是为了让第二根手指敲击屏幕,否则在双指甩动之前就启动了拖拽。所以基本上,如果 ACTION_DOWN 后 100 毫秒没有第二个指针,则进行拖动
    • 啊,好吧,我明白你的意思了。如果我没记错的话,第一根手指向下的 ID 为 0。我会做我上面所说的 postDelayed 事情,但决定因素是你是否识别第二根手指,或者第二个 pointerIndex event.getAction = ActionDown 或 ActionMove .类似的东西。只是一些想法
    • 我发现我可以使用 SystemClock 并测量与第一次触摸发生时的时间差。 :D
    【解决方案4】:

    答案:使用系统时钟 (elapsedRealtime()) 并测量自按下启动以来的毫秒数。一旦你开始掌握它就很容易了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-27
      • 2014-12-04
      相关资源
      最近更新 更多