【问题标题】:Distinguish between short tap (click) and long press in OnTouchListener区分 OnTouchListener 中的短按(单击)和长按
【发布时间】:2019-12-25 06:15:59
【问题描述】:

我已经找到了这个答案:Distinguish between long press and short press on a hardware button 但我对 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 会立即触发。是否只有当新闻很长时才可以调用它?我想也许可以使用时间戳来启用和禁用它,但有没有更简单的解决方案?

【问题讨论】:

    标签: android kotlin ontouchlistener


    【解决方案1】:

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

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

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

    编辑:好的,在阅读了文档之后,我承认它并不像我想象的那么简单。但它也不应该很复杂。从documentationsetIsLongpressEnabled 可以看出问题所在(已添加重点):

    设置是否启用长按,如果在用户按下并按住时启用,则会收到一个长按事件没有更多

    因此,在检测到长按后,您将不会收到任何滚动回调。您可以按如下方式解决此问题。使用手势检测器的常用方法是编写您的 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。您可以在onDown 回调中清除isLongPress。然后,您应该忽略对onScroll 的任何回调,因为根据定义,它们无需长按即可发生。

    【讨论】:

    • 非常感谢,我正在研究它,这似乎是一个非常简单的解决方案
    • 您好 Ted,我只想在这里写下,虽然 GestureDetector 有助于简单的分配,但它相当有限且不灵活。例如,您无法在长按事件后检测到滚动/拖动事件,长按将阻止任何其他事件,不幸的是,这种行为无法改变。看来是直接编辑 GestureDetector.java 的唯一方法,或者不使用它
    • @sir-haver - 你的意思是手势检测器调用监听器的onLongPress 方法后,不会调用onScroll?这有点令人惊讶。如果是这种情况,请告诉我,我可能会提出一两个建议。
    • 嘿 Ted,我的意思正好相反:在手势检测器调用监听器的 onLongPress 方法后,它会调用 onScroll(如果用户在长按时移动手指)。目前,onLongPress 方法阻塞了 onScroll 方法——如果我没记错的话,我可以在 GestureDetector.java 中看到这个阻塞,所以当 onLongPress 被调用时,onScroll 不能被调用。是否可以更改此默认行为?
    • @sir-haver - 这不是你想要的——长按后拖动吗?您可以使用onLongPress 回调设置标志,然后忽略滚动,除非设置了标志。 (您可以在启动任何手势的 onDown 回调中清除标志。)
    猜你喜欢
    • 2019-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多