Есть ли способ вернуть действие салфетки и восстановить держатель вида в исходное положение после, а салфетка завершена, а 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)