Подтвердить что ты не робот

Android RecyclerView ItemTouchHelper возвращает салфетки и восстанавливает вид

Есть ли способ вернуть действие салфетки и восстановить держатель вида в исходное положение после, а салфетка завершена, а onSwiped вызывается в экземпляре ItemTouchHelper.Callback? Я получил экземпляры RecyclerView, ItemTouchHelper и ItemTouchHelper.Callback, чтобы работать вместе отлично, мне просто нужно отменить действие салфетки и не удалить поврежденный элемент в некоторых случаях.

4b9b3361

Ответ 1

После некоторого случайного толчка я нашел решение. Вызовите notifyItemChanged на вашем адаптере. Это заставит выведенный вид вернуться в исходное положение.

Ответ 2

Реализация Google ItemTouchHelper предполагает, что элемент each, который будет удаляться, в конечном итоге удаляется из представления recycler, в некоторых случаях это может быть не так.

RecoverAnimation является вложенным классом в ItemTouchHelper, который управляет анимацией касания элементов подталкивания/перетаскивания. Хотя название подразумевает, что только восстанавливает позицию элементов, это фактически единственный класс, который используется для восстановления (отмена салфетки/перетаскивания) и заменить (вывести на экран или заменить на перетаскивание). Странное имя.

Здесь существует логическое свойство с именем mIsPendingCleanup в RecoverAnimation, которое ItemTouchHelper использует, чтобы выяснить, находится ли элемент в ожидании удаления. Итак, ItemTouchHelper, после прикрепления элемента RecoverAnimation к элементу, устанавливает это свойство после успешного удаления, и анимация не удаляется из списка анимаций восстановления, пока это свойство установлено. Проблема заключается в том, что mIsPendingCleanup всегда будет устанавливаться для выбитого элемента, в результате чего элемент RecoverAnimation для элемента никогда не будет удален из списка анимаций. Таким образом, даже если вы восстановите позицию позиции после успешной салфетки, она будет отправлена ​​обратно в выведенную из строя позицию, как только вы ее коснетесь, потому что RecoverAnimation приведет к началу анимации с последней позиции.

Решение, к сожалению, скопировать исходный код класса ItemTouchHelper в тот же пакет, что и в библиотеке поддержки, и удалить свойство mIsPendingCleanup из класса RecoverAnimation. Я не уверен, что это приемлемо для Google, и я еще не опубликовал обновление в Play Store, чтобы узнать, приведет ли оно к отказу, но вы можете найти исходный код класса из библиотеки поддержки v22.2.1 с приведенным выше упомянутое исправление в https://gist.github.com/kukabi/f46e1c0503d2806acbe2.

Ответ 3

Вы должны переопределить метод onSwiped в ItemTouchHelper.Callback и обновить этот конкретный элемент.

 @Override
 public void onSwiped(RecyclerView.ViewHolder viewHolder,
     int direction) {
     adapter.notifyItemChanged(viewHolder.getAdapterPosition());
 }

Ответ 4

грязный обходной путь для решения этой проблемы состоит в том, чтобы повторно присоединить ItemTouchHelper, дважды вызвав ItemTouchHelper::attachToRecyclerView(RecyclerView), что затем вызовет закрытый метод ItemTouchHelper::destroyCallbacks(). destroyCallbacks() удаляет украшение элемента и всех слушателей, но также очищает все RecoverAnimations.

Обратите внимание, что сначала нам нужно вызвать itemTouchHelper.attachToRecyclerView(null), чтобы обмануть ItemTouchHelper и подумать, что второй вызов itemTouchHelper.attachToRecyclerView(recyclerView) - это новое представление переработчика.

Для получения дополнительной информации ознакомьтесь с исходным кодом ItemTouchHelper здесь.

Пример обходного пути:

RecyclerView recyclerView = findViewById(R.id.recycler_view);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);

...
// Workaround to reset swiped out views
itemTouchHelper.attachToRecyclerView(null);
itemTouchHelper.attachToRecyclerView(recyclerView);

Рассматривайте это как грязный обходной путь, потому что этот метод использует внутреннюю недокументированную деталь реализации ItemTouchHelper.

Обновление:

Из документации ItemTouchHelper::attachToRecyclerView(RecyclerView):

Если TouchHelper уже подключен к RecyclerView, он сначала отсоединится от предыдущего. Вы можете вызвать этот метод с нулевым значением, чтобы отсоединить его от текущего RecyclerView.

и в документации параметров:

Экземпляр RecyclerView, к которому вы хотите добавить этот помощник или ноль, если вы хотите удалить ItemTouchHelper из текущего RecyclerView.

Так что, по крайней мере, это частично документировано.

Ответ 5

Вызовите notifyDataSetChanged на своем адаптере, чтобы сделать прокрутку обратно согласованной.

Ответ 6

В случае использования LiveData для предоставления списка ListAdapter, вызов notifyItemChanged не работает. Тем не менее, я нашел ошибочный обходной путь, который включает в себя повторное присоединение ItemTouchHelper к представлению переработчика в обратном вызове onSwiped как таковое

val recyclerView = someRecyclerViewInYourCode

var itemTouchHelper: ItemTouchHelper? = null

val itemTouchCallback = object : ItemTouchHelper.Callback {
    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction:Int) {
        itemTouchHelper?.attachToRecyclerView(null)
        itemTouchHelper?.attachToRecyclerView(recyclerView)
    }
}

itemTouchHelper = ItemTouchHelper(itemTouchCallback)

itemTouchHelper.attachToRecyclerView(recyclerView)