Как запретить смахивание при свайпе recyclerView?

У меня есть recyclerView наполненный сообщениями. При сдвиге влево реализую ответ на сообщение. Но это происходит только при полном смахивании сообщения. Я хочу запретить смахивание, установив только небольшое отклонение влево. Кажется нужно использовать метод converToAbsoluteDirection(), но как это сделать? Большое спасибо за любую помощь.

val simpleCallback = object :
 ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {
 override fun onMove(
 recyclerView: RecyclerView,
 viewHolder: RecyclerView.ViewHolder,
 target: RecyclerView.ViewHolder
 ): Boolean = false

 override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
 val position = viewHolder.bindingAdapterPosition
 when (direction) {

 ItemTouchHelper.LEFT -> {
 binding?.answer?.visibility = View.VISIBLE
 }
 }
 }

 override fun convertToAbsoluteDirection(flags: Int, layoutDirection: Int): Int {
 return super.convertToAbsoluteDirection(flags, layoutDirection)
 }
 }
 val itemTouchHelper = ItemTouchHelper(simpleCallback)
 itemTouchHelper.attachToRecyclerView(binding?.messageList)
 }


Ответы (1 шт):

Автор решения: Yura Ivanov

ItemTouchHelper.SimpleCallback сам решает когда произошел свайп, и считает, что и нужно просто дать такой translationX чтобы view на экране просто не было, потому что далее будет наверняка вызван adapter.notifyItemDeleted. А вот если свайпа нет, то потом выполняется обратная анимация. Это реализация swipe2delete.

Чтобы решить задачу, надо от его функционала оставить только сдвиг элемента и обратную анимацию, то есть чтоб определение свайпа, реализованное в колбэке, не сработало никогда, при этом вызывать onSwiped когда надо.

Для этого можно выставить параметры:

@Override
public float getSwipeEscapeVelocity(float defaultValue) {
    return 1000.0f; // velocity которая наужна, чтоб был реальный swipe, но velocity всегда будет 1.0 или меньше, поэтому реальный swipe не произойдет
}

@Override
public float getSwipeVelocityThreshold(float defaultValue) {
    return 1.0f; // Минимальная velocity, которая повлияет на swipe, в итоге определится это значение как velocity
}

@Override
public float getSwipeThreshold(RecyclerView.ViewHolder viewHolder) {
    return 100.0f;// Как можно больше, чтоб не получить реальный swipe - множитель для ширины экрана
}

И тогда onSwiped вызывать самостоятельно в onChildDraw:

@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
    if (Math.abs(dX) >= 200f) { // Если сдвинули на эту величину, считаем, что swipe произошел
        onSwiped(viewHolder, (int) Math.signum(dX) < 0.0 ? ItemTouchHelper.LEFT : ItemTouchHelper.RIGHT);
    }
    super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}

ЗЫ можно еще явно добавить viewHolder.itemView.performHapticFeedback в onSwiped
ЗЗЫ в onChildDraw можно не вызывать super если dx больше(меньше) чем дистанция свайпа.
ЗЗЗЫ Еще вариант можно просто написать свою реализацию SimpleCallback'а, который не будет отличаться кроме пары методов...

→ Ссылка