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

OnTouchListerner shall not interpret swipes to open DrawerLayout as Long Click

我正在使用下面的 OnItemTouchListener class 在我的 recyclerview 中检测点击。不幸的是,这在使用 DrawerLayout 时效果不佳。如果我滑动打开 DrawerLayout/NavigationView,我的 OnItemTouchListener 也会收到此事件并执行 onLongClick 操作。

如果我使用 ViewHolders 的 View.OnLongClick,则不会发生这种情况。有什么小秘密,Views 的 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())
        }
    }
}

我是这样解决的:

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
    }
})