Есть ли способ вернуть действие салфетки и восстановить держатель вида в исходное положение после, а салфетка завершена, а onSwiped вызывается в экземпляре ItemTouchHelper.Callback? Я получил экземпляры RecyclerView, ItemTouchHelper и ItemTouchHelper.Callback, чтобы работать вместе отлично, мне просто нужно отменить действие салфетки и не удалить поврежденный элемент в некоторых случаях.
Android RecyclerView ItemTouchHelper возвращает салфетки и восстанавливает вид
Ответ 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)