OnTouchListerner不应将滑动解释为长按以打开DrawerLayout。

4
我正在使用下面的 OnItemTouchListener 类检测 RecyclerView 中的点击事件。然而,当使用 DrawerLayout 时,这种方法效果不佳。如果我滑动以打开 DrawerLayout/NavigationView,我的 OnItemTouchListener 也会收到事件并执行 onLongClick 操作。
如果我使用 ViewHolders 的 View.OnLongClick,则不会发生这种情况。View 的 OnLongClickListener 触发 LongClick 事件之前会先检查拖动操作是否为长按,还是手势打开抽屉的操作?
class OnItemTouchListener(context: Context, recyclerView: RecyclerView, private var onTouchCallback: ItemTouchListener) : RecyclerView.OnItemTouchListener {

    //region Variables

    private val gestureDetector: GestureDetector

    //endregion

    init {
        gestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
            override fun onSingleTapUp(e: MotionEvent?): Boolean {
                return true
            }

            override fun onLongPress(e: MotionEvent?) {
                val child: View? = recyclerView.findChildViewUnder(e!!.x, e.y)

                if (child != null) {
                    onTouchCallback.onItemLongClick(child, recyclerView.getChildLayoutPosition(child), e)
                }

                super.onLongPress(e)
            }
        })
    }

    //region TouchHandler

    override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
        val child = rv.findChildViewUnder(e.x, e.y)

        if (child != null && gestureDetector.onTouchEvent(e)) {
            onTouchCallback.onItemClick(child, rv.getChildLayoutPosition(child), e)
        }

        return false
    }

    override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {

    }

    override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {

    }

    //endregion

    interface ItemTouchListener {
        fun onItemClick(view: View, pos: Int, e: MotionEvent)
        fun onItemLongClick(view: View, pos: Int, e: MotionEvent)
    }

    companion object {
        fun isViewClicked(container: View, @IdRes viewId: Int, e: MotionEvent): Boolean {
            val view = container.findViewById<View>(viewId)

            val rect = Rect()
            view.getGlobalVisibleRect(rect)

            return view.isVisible && rect.contains(e.rawX.toInt(), e.rawY.toInt())
        }
    }
}

在长按操作中,您可以避免调用 super 来通知系统您已经消耗了长按操作。 - Jeel Vankhede
@JeelVankhede 这个方法没有返回类型。问题在于,如果我正在滑动打开抽屉,我不想gestureDetector检测到长按。 - the_dani
1个回答

2
我是这样解决的:

以下是我的解决方法:

gestureDetector = GestureDetectorCompat(context, object : GestureDetector.SimpleOnGestureListener() {
    private val MIN_SWIPE_DISTANCE: Int = 50
    private lateinit var downMotionEvent: MotionEvent

    override fun onDown(e: MotionEvent?): Boolean {
        e?.let { downMotionEvent = it }

        return super.onDown(e)
    }

    override fun onSingleTapUp(e: MotionEvent?): Boolean {
        return true
    }

    override fun onLongPress(e: MotionEvent?) {
        e?.let {
            val child: View? = recyclerView.findChildViewUnder(it.x, it.y)

            if (child != null && !isGestureSwipe(it)) {
                onTouchCallback.onItemLongClick(child, recyclerView.getChildLayoutPosition(child), it)
            }
        }

        super.onLongPress(e)
    }

    fun isGestureSwipe(e: MotionEvent): Boolean {
        return downMotionEvent.x - e.x <= MIN_SWIPE_DISTANCE
    }
})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接