ACTION_UP 未因 quick/normal 单击 OnTouchListener.onTouch 而触发

ACTION_UP is not triggered for a quick/normal click on OnTouchListener.onTouch

我有一个按钮可以在 MainActivity 中触发一些动作,我想按如下方式绘制动画:当用户按住按钮 (ACTION_DOWN) 时,它会缩小,当按钮被释放时 (ACTION_UP 或 ACTION_CANCEL) 它会放大并恢复到正常状态。

当用户按住按钮一段时间时效果很好,但对于正常的点击,ACTION_UP 永远不会被调用,即使 ACTION_DOWN 会被调用。

我搜索了文档并检查了 Whosebug 上的几乎所有答案,但没有找到任何有用的东西。

documentation 是这样说的:“虽然框架试图向视图提供一致的运动事件流,但它不能保证这一点。某些事件可能会被删除或修改,方法是在它们出现之前在应用程序中包含视图交付从而使事件流不一致。视图应该始终准备好处理 ACTION_CANCEL 并且应该容忍异常情况,例如接收新的 ACTION_DOWN 而没有首先收到先前的 ACTION_UP手势。

这是我的代码:

button.setOnTouchListener { view, event ->
            when(event?.action){
                //behaves as expected
                MotionEvent.ACTION_DOWN -> {
                    scaleDown(view)
                }
                //the problem here: ACTION_UP gets called only when user holds the button for some time
                //and not for a quick/ normal click.
                MotionEvent.ACTION_UP -> {
                    scaleUp(view)
                    doSomething()
                }
                //behaves as expected
                MotionEvent.ACTION_CANCEL -> {
                    scaleUp(view)
                }
            }
            true
        }

我有两个问题,第一:为什么 ACTION_UP 从来没有被要求点击 quick/normal?

其次:如果我想以两种不同的方式做出反应,如何区分正常点击和用户按住按钮一段时间?

问题#1

我尝试了下面的代码片段,通过长时间、正常和快速的点击,它按预期工作

button.setOnTouchListener { view, event ->

    if (event.action == MotionEvent.ACTION_DOWN) {
        Log.d("TESTOOO", "DOWN")
    } else if (event.action == MotionEvent.ACTION_UP) {
        Log.d("TESTOOO", "UP")
    }

    true
}

问题#2

你能试试吗setOnLongClickListener(),我试过了,效果很好

回答我自己的问题:

对于第一个问题,问题出在动画上,而不是 OnTouchListener。

对于第二个问题,为了区分正常点击和长按,我必须计算自从 ACTION_UP 或 ACTION_CANCEL 时触发 ACTION_DOWN 以来经过了多少毫秒被触发。

如果两个事件之间的差异小于 300 毫秒,则认为是正常点击,否则就是长时间点击。

button.setOnTouchListener { view, event ->
    val now = System.currentTimeMillis()
    when(event?.action){
        MotionEvent.ACTION_DOWN -> {
            scaleDown(view)
        }
        MotionEvent.ACTION_UP -> {
             scaleUp(view)
             if(now - event.downTime < 300){
                 //normal click
             }else{
                 //long click
             }
        }
        MotionEvent.ACTION_CANCEL -> 
             scaleUp(view)
        }
   }
   true
}