Arrastra y desliza en RecyclerView. Parte 1: ItemTouchHelper

Arrastra y desliza en RecyclerView. Parte 1: ItemTouchHelper


Hay muchos tutoriales, bibliotecas e implementaciones de arrastrar y soltar y deslizar para descartar en Android usando RecyclerView. La mayoría de ellos todavía utilizan el obsoleto View.OnDragListener y el enfoque SwipeToDismiss desarrollado por Roman Nurik. Aunque ya hay métodos nuevos y más efectivos disponibles. Muy pocos usan las API más recientes, a menudo dependen de GestureDetectors y onInterceptTouchEvent u otras implementaciones más complejas. En realidad, hay una manera muy simple de agregar estas funciones a RecyclerView . Esto requiere solo una clase, que también forma parte de la Biblioteca de soporte de Android.


ItemTouchHelper


ItemTouchHelper es una poderosa utilidad que se encarga de todo lo que necesita hacer para agregar funciones de arrastrar y soltar y deslizar para descartar a RecyclerView . Esta utilidad es una subclase de RecyclerView.ItemDecoration , por lo que es fácil de agregar a casi cualquier LayoutManager y adaptador existentes. También funciona con animación de elementos y proporciona la capacidad de arrastrar y soltar elementos de un tipo a otro lugar en la lista y mucho más. En este artículo, demostraré una implementación simple de ItemTouchHelper . Más adelante, como parte de esta serie de artículos, ampliaremos el alcance y consideraremos otras opciones.


Nota ¿Quieres ver el resultado de inmediato? Echa un vistazo a Github: Android-ItemTouchHelper-Demo . La primera confirmación se refiere a este artículo. El archivo de demostración .apk se puede descargar aquí .


Ejemplo


Personalización


Primero necesitamos configurar el RecyclerView . Si aún no lo ha hecho, agregue la dependencia RecyclerView a su archivo build.gradle .


 compile 'com.android.support:recyclerview-v7:22.2.0' 

ItemTouchHelper funcionará con casi cualquier RecyclerView.Adapter y LayoutManager , pero este artículo se basa en ejemplos que usan estos archivos .


Uso de ItemTouchHelper y ItemTouchHelper.Callback


Para usar ItemTouchHelper , debe crear un ItemTouchHelper.Callback . Esta es una interfaz que le permite rastrear las acciones de movimiento ( ing. Move) y deslizar ( eng. Swipe). Además, aquí puede controlar el estado del componente de view seleccionado y anular la animación predeterminada. Hay una clase auxiliar que puede usar si desea usar la implementación básica, SimpleCallback . Pero para entender cómo funciona esto en la práctica, haremos todo por nuestra cuenta.


Las funciones principales de la interfaz que debemos redefinir para incluir la funcionalidad básica de arrastrar y soltar y deslizar para descartar :


 getMovementFlags(RecyclerView, ViewHolder) onMove(RecyclerView, ViewHolder, ViewHolder) onSwiped(ViewHolder, int) 

También usaremos varios métodos auxiliares:


 isLongPressDragEnabled() isItemViewSwipeEnabled() 

Consideremos uno por uno.


 @Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; return makeMovementFlags(dragFlags, swipeFlags); } 

ItemTouchHelper facilita la determinación de la dirección de un evento. getMovementFlags() anular el método getMovementFlags() para indicar qué direcciones arrastrar y soltar serán compatibles. Para crear ItemTouchHelper.makeMovementFlags(int, int) retorno, use el método auxiliar ItemTouchHelper.makeMovementFlags(int, int) . En este ejemplo, permitimos arrastrar y soltar en ambas direcciones.


 @Override public boolean isLongPressDragEnabled() { return true; } 

ItemTouchHelper solo se puede usar para arrastrar y soltar sin funcionalidad de deslizar (o viceversa), por lo que debe especificar exactamente qué funciones deben ser compatibles. El método isLongPressDragEnabled() debe volver true para admitir arrastrar y soltar después de un largo clic en el elemento RecyclerView . Alternativamente, puede llamar al ItemTouchHelper.startDrag(RecyclerView.ViewHolder) para comenzar a arrastrar manualmente. Consideraremos esta opción más adelante.


 @Override public boolean isItemViewSwipeEnabled() { return true; } 

Para habilitar el batido después de tocar cualquier parte dentro del componente de view , simplemente devuelva true desde el método isItemViewSwipeEnabled() . Alternativamente, puede llamar al ItemTouchHelper.startSwipe(RecyclerView.ViewHolder) para iniciar el deslizamiento manualmente.


Los dos métodos siguientes, onMove() y onSwiped() , son necesarios para notificarle las actualizaciones de datos. Entonces, primero crearemos una interfaz que permitirá que estos eventos pasen a lo largo de la cadena de llamadas.


ItemTouchHelperAdapter.java


 public interface ItemTouchHelperAdapter { void onItemMove(int fromPosition, int toPosition); void onItemDismiss(int position); } 

La forma más fácil de hacer esto es hacer que RecyclerListAdapter implemente el oyente.


 public class RecyclerListAdapter extends RecyclerView.Adapter<ItemViewHolder> implements ItemTouchHelperAdapter { // ...   [](https://gist.github.com/iPaulPro/2216ea5e14818056cfcc#file-recyclerlistadapter-java) @Override public void onItemDismiss(int position) { mItems.remove(position); notifyItemRemoved(position); } @Override public boolean onItemMove(int fromPosition, int toPosition) { if (fromPosition < toPosition) { for (int i = fromPosition; i < toPosition; i++) { Collections.swap(mItems, i, i + 1); } } else { for (int i = fromPosition; i > toPosition; i--) { Collections.swap(mItems, i, i - 1); } } notifyItemMoved(fromPosition, toPosition); return true; } 

Es muy importante llamar a los notifyItemRemoved() y notifyItemMoved() para que el adaptador vea los cambios. También debe tenerse en cuenta que cambiamos la posición del elemento cada vez que el componente de view se cambia a un nuevo índice, y no al final del movimiento (el evento de "caída") .


Ahora podemos volver a crear SimpleItemTouchHelperCallback , ya que todavía tenemos que anular los onMove() y onSwiped() . Primero agregue el constructor y el campo para el adaptador:


 private final ItemTouchHelperAdapter mAdapter; public SimpleItemTouchHelperCallback( ItemTouchHelperAdapter adapter) { mAdapter = adapter; } 

Luego redefina los eventos restantes e informe esto al adaptador:


 @Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition()); return true; } @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { mAdapter.onItemDismiss(viewHolder.getAdapterPosition()); } 

Como resultado, la clase de Callback debería verse así:


 public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback { private final ItemTouchHelperAdapter mAdapter; public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) { mAdapter = adapter; } @Override public boolean isLongPressDragEnabled() { return true; } @Override public boolean isItemViewSwipeEnabled() { return true; } @Override public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) { int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; return makeMovementFlags(dragFlags, swipeFlags); } @Override public boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target) { mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition()); return true; } @Override public void onSwiped(ViewHolder viewHolder, int direction) { mAdapter.onItemDismiss(viewHolder.getAdapterPosition()); } } 

Cuando Callback está listo, podemos crear un ItemTouchHelper y llamar al attachToRecyclerView(RecyclerView) (por ejemplo, en MainFragment.java ):


 ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(adapter); ItemTouchHelper touchHelper = new ItemTouchHelper(callback); touchHelper.attachToRecyclerView(recyclerView); 

Después de comenzar, debería obtener algo como lo siguiente:


Resultado


Conclusión


Esta es la implementación más simplificada de ItemTouchHelper . Sin embargo, puede notar que no tiene que usar una biblioteca de terceros para implementar las acciones estándar de arrastrar y soltar y deslizar para descartar en RecyclerView . En la siguiente parte, prestaremos más atención a la apariencia de los elementos al momento de arrastrar y soltar.


Código fuente


Creé un proyecto en GitHub para demostrar lo que se cubre en esta serie de artículos: Android-ItemTouchHelper-Demo . La primera confirmación se relaciona principalmente con esta parte y un poco con la segunda .


→ Arrastre y deslice en RecyclerView. Parte 2: arrastrar y soltar controladores, cuadrículas y animaciones personalizadas

Source: https://habr.com/ru/post/es427681/


All Articles