一个View如何实现onClick、onLongClick和onTouch

How to implement onClick, onLongClick and onTouch to one View

我有一个视图(它是 RecyclerView 中的 ViewHolder,但我认为它不会有任何区别)实现了 onClick()onLongClick()onTouch()。我遇到的问题是 longClick 永远不会被执行。我在其他问题中读到了它,但我不知道该怎么做以及我应该在什么时候 return true \ false in onTouch()。这是我的代码;

ViewHolder class 中的函数 bind() 实现了 View.OnTouchListener:

binding.background.setOnClickListener {
    Log.d("Click")
}

binding.background.setOnLongClickListener {
    Log.d("Long Click")
}

binding.background.setOnTouchListener(this) // here I see warning "Custom view `ConstraintLayout` has setOnTouchListener called on it but does not override performClick"

覆盖 onTouch()

override fun onTouch(v: View?, event: MotionEvent?): Boolean
{
    return when (event!!.action)
    {
        MotionEvent.ACTION_DOWN ->
        {
            x1 = event.x
            true
        }
            MotionEvent.ACTION_UP ->
        {
            x2 = event.x
            return if (abs(x2 - x1) > MIN_DISTANCE)
            {
                Log.d("Was swiped")
                true
            }
            else
            {
                Log.d("Wasn't swiped")
                v?.performClick()
                false
            }
        }
        else -> false
    }
}

此函数仅检测视图上的幻灯片。我应该在 onTouch() 中更改什么以使 longClick 正常工作?另外,有没有更简单的方法来检测 RecyclerView 项目上的幻灯片?

尝试在 onTouchEvent 视图中使用 GestureDetector,如下所示

final GestureDetector longPressGestureDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener() {
public void onLongPress(MotionEvent e) {
        Log.d(TAG, "onLongPress -> long press detected");
    }
});
public boolean onTouchEvent(MotionEvent event) {
    return longPressGestureDetector.onTouchEvent(event); //Will handle gesture API calls. The Gesture Detector can be used for Swipe actions as well.
};

如果有人遇到这样的问题我是这样解决的:
(它是回收器视图项目,可以左右移动或滚动)

ViewHolder 字段:

private var xStart = 0F
private var lastY = 0F
private var yStart = 0F
private val handler: Handler = Handler()
private var isLongClickCanceled = false
private var wasLongClicked = false
private var startScrolling = false
private var status = 0
...
private const val LONG_CLICK_TIME = 700L
private const val CLICK_DISTANCE = 75
private const val PANEL_SIZE = 125

触控功能

override fun onTouch(v: View?, event: MotionEvent?): Boolean
{
    if (v != null && event != null)
    {
        v.parent.requestDisallowInterceptTouchEvent(true)
        when (event.action)
        {
            MotionEvent.ACTION_DOWN ->
            {
                Log.d("Down")
                xStart = event.x
                yStart = event.y
                isLongClickCanceled = false
                wasLongClicked = false
                startScrolling = false
                handler.postDelayed({ //long click
                    wasLongClicked = true
                    val leftPanel = (v as ViewGroup).getChildAt(0)
                    val rightPanel = v.getChildAt(1)
                    val paramsLP = leftPanel.layoutParams
                    val paramsRP = rightPanel.layoutParams
                    paramsLP.width = 1
                    paramsRP.width = 1
                    leftPanel.layoutParams = paramsLP
                    rightPanel.layoutParams = paramsRP
                    v.performLongClick()
                }, LONG_CLICK_TIME)
                xStart = event.x
            }
            MotionEvent.ACTION_UP ->
            {
                Log.d("Up")
                handler.removeCallbacksAndMessages(null)
                if (!startScrolling && !isLongClickCanceled && !wasLongClicked)
                {
                    if ((event.eventTime - event.downTime) < LONG_CLICK_TIME) //click
                    {
                        Log.d("Status $status")
                        if (status == 0)
                        {
                            v.performClick()
                        }
                        else
                        {
                            val leftPanel = (v as ViewGroup).getChildAt(0)
                            val rightPanel = v.getChildAt(1)
                            val paramsLP = leftPanel.layoutParams
                            val paramsRP = rightPanel.layoutParams
                            paramsLP.width = 1
                            paramsRP.width = 1
                            leftPanel.layoutParams = paramsLP
                            rightPanel.layoutParams = paramsRP
                            status = 0
                            selectCar(binding.car!!.carID, false)
                        }
                    }
                }
                else
                {
                    val leftPanel = (v as ViewGroup).getChildAt(0)
                    val rightPanel = v.getChildAt(1)
                    val paramsLP = leftPanel.layoutParams
                    val paramsRP = rightPanel.layoutParams
                    when
                    {
                        status > (PANEL_SIZE / 2) ->
                        {
                            paramsLP.width = PANEL_SIZE
                            paramsRP.width = 1
                            selectCar(binding.car!!.carID, false)
                        }
                        status < -(PANEL_SIZE / 2) ->
                        {
                            paramsRP.width = PANEL_SIZE
                            paramsLP.width = 1
                            selectCar(binding.car!!.carID, true)
                        }
                        else ->
                        {
                            paramsLP.width = 1
                            paramsRP.width = 1
                            status = 0
                            selectCar(binding.car!!.carID, false)
                        }
                    }
                    leftPanel.layoutParams = paramsLP
                    rightPanel.layoutParams = paramsRP
                }
            }
            MotionEvent.ACTION_MOVE ->
            {
                if (startScrolling)
                {
                    scroll((lastY - event.rawY).toInt())
                    lastY = event.rawY
                }
                else
                {
                    if (!wasLongClicked)
                    {
                        if (isLongClickCanceled)
                        {
                            val deltaX = (event.x - xStart).toInt()
                            if (abs(deltaX) > 75)
                            {
                                val leftPanel = (v as ViewGroup).getChildAt(0)
                                val rightPanel = v.getChildAt(1)
                                val paramsLP = leftPanel.layoutParams
                                val paramsRP = rightPanel.layoutParams
                                if (deltaX > 0)
                                {
                                    status = (deltaX - CLICK_DISTANCE)
                                    paramsLP.width = min(status, PANEL_SIZE)
                                    paramsRP.width = 1
                                }
                                else if (deltaX < 0)
                                {
                                    status = (deltaX + CLICK_DISTANCE)
                                    paramsRP.width = min(-status, PANEL_SIZE)
                                    paramsLP.width = 1
                                }
                                leftPanel.layoutParams = paramsLP
                                rightPanel.layoutParams = paramsRP
                            }
                        }
                        else if (abs(yStart - event.y) > CLICK_DISTANCE)
                        {
                            lastY = event.rawY
                            startScrolling = true
                            handler.removeCallbacksAndMessages(null)
                        }
                        else if (!isLongClickCanceled && abs(xStart - event.x) >= CLICK_DISTANCE)
                        {
                            isLongClickCanceled = true
                            handler.removeCallbacksAndMessages(null)
                        }
                    }
                }
            }
        }
    }
    return true
}

传递给 ViewHolder 的滚动函数

{ dy -> binding.recViewCar.scrollBy(0, dy) }

这段代码可以执行Click、LongClick和Touching视图。当用户长按时,不会执行移动动作。将手指放在屏幕上并移动超过 CLICK_DISTANCE 后,点击和长按不会被执行