获取绑定recyclerView的ItemTouchHelper私有变量mItemTouchHelperGestureListener,并获取ItemTouchHelperGestureListener的长按方法onLongPress,自定义item的onTouch方法在点击时调用onLongPress。
val mItemTouchHelper = ItemTouchHelper(mCallback) mItemTouchHelper.attachToRecyclerView(rv) try { val c = mItemTouchHelper::class.java val field = c.getDeclaredField("mItemTouchHelperGestureListener") field.isAccessible = true val listener = field.get(mItemTouchHelper) val listenerClass = Class.forName("androidx.recyclerview.widget.ItemTouchHelper\$ItemTouchHelperGestureListener") val onLongPressMethod = listenerClass.getDeclaredMethod("onLongPress", MotionEvent::class.java) setLongClickDelay(Handler(), rv, 500, listener, onLongPressMethod) } catch (e: Exception) { e.printStackTrace() }
private fun setLongClickDelay( handler: Handler, v: RecyclerView, delay: Long, listener: Any, method: Method ) { val delayMillis = if (delay < 50) 50 else delay v.addOnItemTouchListener(object : OnItemTouchListener { private val TOUCH_MAX = 50 var mEvent: MotionEvent? = null private var mLastMotionX = 0 private var mLastMotionY = 0 private var mHasPerformedLongPress = false private val performLongClick = Runnable { // mHasPerformedLongPress = v.performLongClick(); if (mEvent != null) { mHasPerformedLongPress = true //响应长按onLongPress method.invoke(listener, mEvent) mEvent = null } } override fun onInterceptTouchEvent(rv: RecyclerView, event: MotionEvent): Boolean { val x = event.x.toInt() val y = event.y.toInt() when (event.action) { MotionEvent.ACTION_UP -> { mEvent = null handler.removeCallbacks(performLongClick) // case 1 v.tag = mHasPerformedLongPress if (!mHasPerformedLongPress) { v.performClick() } else { // 长按消耗了,此事件 return true } } MotionEvent.ACTION_MOVE -> if (Math.abs(mLastMotionX - x) > TOUCH_MAX || Math.abs( mLastMotionY - y ) > TOUCH_MAX ) { mEvent = null handler.removeCallbacks(performLongClick) } MotionEvent.ACTION_DOWN -> { mHasPerformedLongPress = false handler.removeCallbacks(performLongClick) mLastMotionX = x mLastMotionY = y // 不能直接用mEvent = event,这样赋值 mEvent 的 getX 和 getY 得到的值是相对屏幕(或者是父布局)的, // 具体原理不清楚 mEvent = MotionEvent.obtain(event) handler.postDelayed(performLongClick, delayMillis) } MotionEvent.ACTION_CANCEL -> handler.removeCallbacks(performLongClick) } return false } override fun onTouchEvent(rv: RecyclerView, event: MotionEvent) {} override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {} }) }