Android RecyclerView ItemTouchHelper revert swipe and restore view holder


¿Hay alguna forma de revertir una acción de deslizamiento y restaurar el titular de la vista a su posición inicial después de que se complete el deslizamiento y se llame a onSwiped en la instancia ItemTouchHelper.Callback? Tengo el RecyclerView, ItemTouchHelper y ItemTouchHelper.Callbackinstancias para trabajar juntos perfectamente, solo tengo que revertir la acción de deslizamiento y no eliminar el elemento deslizado en algunos casos.

Author: K K B, 2015-08-03

6 answers

Después de algunos pinchazos aleatorios encontré una solución. Llame a notifyItemChanged en su adaptador. Esto hará que la vista desplazada se anime de nuevo a su posición original.

 73
Author: DariusL,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-22 17:59:06

La implementación de Google ItemTouchHelper asume que cada elemento deslizado finalmente se eliminará de la vista recycler, mientras que podría no ser el caso en algunas aplicaciones.

RecoverAnimation es una clase anidada en ItemTouchHelper que administra la animación táctil de los elementos deslizados/arrastrados. Aunque el nombre implica que solo recupera la posición de los elementos, en realidad es la única clase que se utiliza para recuperar (cancelar deslizar/arrastrar) y reemplazar (mover al deslizar o reemplazar al arrastrar) elementos. Extraño nombre.

Hay una propiedad booleana llamada mIsPendingCleanup en RecoverAnimation, que ItemTouchHelper usa para averiguar si el elemento está pendiente de eliminación. Por lo tanto, ItemTouchHelper, después de adjuntar un RecoverAnimation al elemento, establece esta propiedad después de deslizar correctamente hacia fuera, y la animación no se elimina de la lista de animaciones de recuperación siempre y cuando esta propiedad esté establecida. El problema es que, mIsPendingCleanup es siempre para un pase elemento, causando la RecoverAnimation para el elemento que nunca se quita de la lista de animaciones. Por lo tanto, incluso si recupera la posición del elemento después de un golpe exitoso, se enviará de vuelta a la posición deslizada tan pronto como lo toque, porque RecoverAnimation hará que la animación comience desde la última posición deslizada.

La solución para esto es, desafortunadamente, copiar el código fuente de la clase ItemTouchHelper en el mismo paquete que está en la biblioteca de soporte, y eliminar la propiedad mIsPendingCleanup de la clase RecoverAnimation. No estoy seguro si esto es aceptable por Google, y no he publicado la actualización a Play Store todavía para ver si causará un rechazo, pero puede encontrar el código fuente de la clase de la biblioteca de soporte v22.2.1 con la corrección mencionada anteriormente en https://gist.github.com/kukabi/f46e1c0503d2806acbe2 .

 19
Author: K K B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-07 07:51:12

A dirty workaround la solución para este problema es volver a adjuntar el ItemTouchHelper llamando a ItemTouchHelper::attachToRecyclerView(RecyclerView) dos veces, que luego llama al método privado ItemTouchHelper::destroyCallbacks(). destroyCallbacks() elimina la decoración de elementos y todos los oyentes, pero también borra todas las RecoverAnimations.

Tenga en cuenta que necesitamos llamar a itemTouchHelper.attachToRecyclerView(null) primero para engañar a ItemTouchHelper para que piense que la segunda llamada a itemTouchHelper.attachToRecyclerView(recyclerView) es una nueva vista de reciclador.

Para más detalles echa un vistazo al código fuente de ItemTouchHelper aquí.

Ejemplo de solución:

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

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

Considéralo como una solución sucia porque este método utiliza detalles de implementación internos e indocumentados de ItemTouchHelper.

Actualización :

De la documentación de ItemTouchHelper::attachToRecyclerView(RecyclerView):

Si TouchHelper ya está conectado a un RecyclerView, primero se separará del anterior. Puede llamar a este método con null para separarlo del método actual RecyclerView.

Y en la documentación de parámetros:

La instancia RecyclerView a la que desea agregar este helper o null si desea eliminar ItemTouchHelper del RecyclerView actual.

Así que al menos está parcialmente documentado.

 7
Author: Jan Bollacke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-05 11:07:58

Debe reemplazar el método onSwiped en ItemTouchHelper.Callback y actualizar ese elemento en particular.

 @Override
 public void onSwiped(RecyclerView.ViewHolder viewHolder,
     int direction) {
     adapter.notifyItemChanged(viewHolder.getAdapterPosition());
 }
 5
Author: jimmy0251,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-02 08:34:29

Llame a notifyDataSetChanged en su adaptador para que el deslizamiento hacia atrás funcione de manera consistente

 1
Author: Jegannath Kandasamy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-19 09:14:26

Si quieres ver un buen tutorial, sobre las animaciones de deslizamiento y Drap de RecyclerView, puedes revisar este video, lo encontré bastante útil. https://www.youtube.com/watch?v=grRAvv-uk1c&t=1228s

 -1
Author: Dor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-17 08:12:25