首页 > 解决方案 > 区分 OnTouchListener 中的短按(单击)和长按

问题描述

我已经找到了这个答案:在硬件按钮上区分长按和短按 但我对 OnTouchListener 感兴趣。原因是我希望短按和释放(单击)会触发某种行为,但长按(不释放)会触发运动事件,使用户能够用手指拖动小部件。

所以我使用 ACTION_MOVE:

val listener = View.OnTouchListener(function = { view, motionEvent ->
    // check if the user gesture upon the view is of moving action
    when (motionEvent.action) {
        MotionEvent.ACTION_DOWN-> {
            // pressed
        }
        MotionEvent.ACTION_MOVE -> {
            view.y = motionEvent.rawY - ((view.height / 2) + 60)
            view.x = motionEvent.rawX - view.width / 2
        }
        MotionEvent.ACTION_UP -> {
            // Released

问题是 ACTION_MOVE 会立即触发。是否只有当新闻很长时才可以调用它?我想可能会以某种方式使用时间戳来启用和禁用它,但有没有更简单的解决方案?

标签: androidkotlinontouchlistener

解决方案


处理此问题的 Android 方法是使用手势检测器。指南主题检测常见手势讨论了如何执行此操作并提供示例代码。

您希望在触摸侦听器的相对较低级别上进行操作的唯一原因是,如果您要实现的逻辑尚未被库手势检测器之一打包。幸运的是,长按和拖动是已经支持的手势。

如果您仍然想编写自己的逻辑,相应手势检测器的源代码可以为您提供一个很好的起点。但是,我强烈反对这样做,因为逻辑可能非常棘手,需要处理很多边缘情况。

编辑:好的,在阅读了文档之后,我承认它并不像我想象的那么简单。但它也不应该很复杂。从文档中可以清楚地看到问题setIsLongpressEnabled(强调添加):

设置是否启用长按,如果在用户按下并按住时启用,您会收到一个长按事件而没有进一步的内容。

因此,在检测到长按后,您将不会收到任何滚动回调。您可以按如下方式解决此问题。使用手势检测器的常用方法是编写您的onTouchEvent方法,如下所示:

override fun onTouchEvent(event: MotionEvent): Boolean {
    return if (mDetector.onTouchEvent(event)) {
        true
    } else {
        super.onTouchEvent(event)
    }
}

您可以将其更改为如下所示:

var isLongPress = false

override fun onTouchEvent(event: MotionEvent): Boolean {
    if (mDetector.onTouchEvent(event)) {
        val action = MotionEventCompat.getActionMasked(event)
        if (isLongPress && action == MotionEvent.ACTION_MOVE) {
            // process the drag
        }    
        return true
    }
    return super.onTouchEvent(event)
}

然后在onLongPress回调中,捕获事件坐标并设置isLongPress. isLongPress您可以在onDown回调中清除。然后,您应该忽略任何回调,onScroll因为根据定义,它们将在没有长按的情况下发生。


推荐阅读