I have a View (it's ViewHolder in RecyclerView but I think it wouldn't make any difference) which implements onClick()
, onLongClick()
, and onTouch()
. The problem I faced is that longClick
is never executed. I read about it in other questions but I can't figure out how to do it and when exactly I should return true
\ false
in onTouch()
. Here is my code;
Function bind()
in ViewHolder class which implements 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"
Override 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
}
}
This function just detects slide on the view. What should I change in onTouch()
to make longClick
working? Also, is there any simpler way to detect slide on the RecyclerView item?
If someone ever will have such a problem I solved it in this way:
(It is recycler view item which can be moved left / right or scrolled)
ViewHolder fields:
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
Touch function
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
}
Scroll function which is passed to ViewHolder
{ dy -> binding.recViewCar.scrollBy(0, dy) }
This code can execute Click, LongClick, and Touching view. When user make LongClick, move action wouldn't be executed. After holding a finger on the screen and moving it more than CLICK_DISTANCE
Click and LongClick wouldn't be executed