
En la primera parte, analizamos ItemTouchHelper y la implementación de ItemTouchHelper.Callback , que agrega las funciones básicas de arrastrar y soltar y deslizar para descartar a RecyclerView
. En este artículo, continuaremos lo que se hizo en el anterior agregando soporte para organizar elementos en forma de cuadrícula, controladores de arrastrar y soltar, selección de un elemento de la lista y animaciones de deslizamiento personalizadas.

Arrastrar y soltar controladores
Al crear una lista que admite arrastrar y soltar , generalmente implementan la capacidad de arrastrar y soltar elementos con el tacto. Esto contribuye a la claridad y facilidad de uso de la lista en el "modo de edición", y también lo recomiendan las pautas de materiales. Agregar controladores de arrastrar y soltar a nuestro ejemplo es increíblemente fácil.

Primero, actualice el layout
elemento ( item_main.xml ).
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/item" android:layout_width="match_parent" android:layout_height="?listPreferredItemHeight" android:clickable="true" android:focusable="true" android:foreground="?selectableItemBackground"> <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginLeft="16dp" android:textAppearance="?android:attr/textAppearanceMedium" /> <ImageView android:id="@+id/handle" android:layout_width="?listPreferredItemHeight" android:layout_height="match_parent" android:layout_gravity="center_vertical|right" android:scaleType="center" android:src="@drawable/ic_reorder_grey_500_24dp" /> </FrameLayout>
La imagen utilizada para el controlador de arrastre se puede encontrar en los iconos de Diseño de materiales y agregar al proyecto utilizando el conveniente complemento generador de iconos en Android Studio.
Como se mencionó brevemente en un artículo anterior, puede usar ItemTouchHelper.startDrag(ViewHolder)
para iniciar mediante programación arrastrar y soltar. Entonces, todo lo que tenemos que hacer es actualizar ViewHolder
agregando un controlador de arrastre y configurar un controlador táctil simple que llamará a startDrag()
.
Necesitaremos una interfaz para transmitir eventos a lo largo de la cadena:
public interface OnStartDragListener { void onStartDrag(RecyclerView.ViewHolder viewHolder); }
Luego defina un ImageView
para el controlador de arrastre en ItemViewHolder
:
public final ImageView handleView; public ItemViewHolder(View itemView) { super(itemView);
y actualice el RecyclerListAdapter
:
private final OnStartDragListener mDragStartListener; public RecyclerListAdapter(OnStartDragListener dragStartListener) { mDragStartListener = dragStartListener;
RecyclerListAdapter
ahora debería verse así.
Todo lo que queda por hacer es agregar OnStartDragListener
al fragmento:
public class RecyclerListFragment extends Fragment implements OnStartDragListener {
RecyclerListFragment
ahora debería verse así . Ahora, cuando inicie la aplicación, puede comenzar a arrastrar y soltar tocando el controlador.

Destacar un elemento de la lista
Ahora, en nuestro ejemplo, no hay indicación visual del elemento que se está arrastrando. Obviamente, esto no debería ser así, pero es fácil de solucionar. Con ItemTouchHelper
puede usar efectos de resaltado de elementos estándar. En Lollipop y versiones posteriores de Android, la luz de fondo "se extiende" sobre el elemento en el proceso de interacción con él; En versiones anteriores, el elemento simplemente cambia su color a oscuro.
Para implementar esto en nuestro ejemplo, simplemente agregue un fondo (propiedad de background
) al FrameLayout
raíz FrameLayout
elemento FrameLayout
o FrameLayout
en el constructor de RecyclerListAdapter.ItemViewHolder . Se verá más o menos así:

Se ve genial, pero es posible que desee controlar aún más. Una forma de hacerlo es permitir que ViewHolder
maneje los cambios de estado de un elemento. Para esto, ItemTouchHelper.Callback
proporciona dos métodos más:
onSelectedChanged(ViewHolder, int)
se llama cada vez que el estado de un elemento cambia a arrastrar ( ACTION_STATE_DRAG ) o deslizar ( ACTION_STATE_SWIPE ). Este es un lugar ideal para cambiar el estado del componente de view
a activo .clearView(RecyclerView, ViewHolder)
cuando se completa el componente de view
arrastrar y soltar, y también cuando se completa el deslizamiento ( ACTION_STATE_IDLE ). Aquí, el estado inicial de su componente de view
generalmente se restaura.
Ahora, pongamos todo junto.
Primero, cree una interfaz que ViewHolders
implementará:
public interface ItemTouchHelperViewHolder { void onItemSelected(); void onItemClear(); }
Luego, en SimpleItemTouchHelperCallback
implemente los métodos apropiados:
@Override public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
Ahora todo lo que queda es que RecyclerListAdapter.ItemViewHolder
implemente ItemTouchHelperViewHolder
:
public class ItemViewHolder extends RecyclerView.ViewHolder implements ItemTouchHelperViewHolder {
En este ejemplo, simplemente agregamos un fondo gris mientras el elemento está activo y luego lo eliminamos. Si su ItemTouchHelper
y el adaptador están estrechamente conectados, puede abandonar fácilmente esta configuración y cambiar el estado del componente de view
directamente en ItemTouchHelper.Callback
.
Redes
Si ahora intenta utilizar el GridLayoutManager
, verá que no funciona correctamente. La razón y la solución son simples: debemos decirle a nuestro ItemTouchHelper
que queremos admitir arrastrar elementos de izquierda a derecha. Anteriormente en SimpleItemTouchHelperCallback
ya especificamos:
@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); }
El único cambio necesario para soportar las cuadrículas es agregar las banderas apropiadas:
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
Sin embargo, deslizar para descartar no es un comportamiento muy natural para los elementos de la cuadrícula, por swipeFlags
muy probable que las swipeFlags
:
@Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; int swipeFlags = 0; return makeMovementFlags(dragFlags, swipeFlags); }
Para ver un ejemplo de GridLayoutManager
funciona, vea RecyclerGridFragment . Así es como se ve al inicio:

Animaciones de deslizamiento personalizadas
ItemTouchHelper.Callback
proporciona una forma realmente conveniente de controlar completamente la animación mientras se arrastra o barre. Dado que ItemTouchHelper
es un RecyclerView.ItemDecoration , podemos intervenir en el proceso de renderizar un componente de view
manera similar. En la siguiente parte, examinaremos esta pregunta con más detalle, pero por ahora, veamos un ejemplo simple de anular la animación de deslizamiento predeterminada para mostrar una desaparición lineal.
@Override public void onChildDraw(Canvas c, RecyclerView recyclerView, ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { float width = (float) viewHolder.itemView.getWidth(); float alpha = 1.0f - Math.abs(dX) / width; viewHolder.itemView.setAlpha(alpha); viewHolder.itemView.setTranslationX(dX); } else { super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); } }
Los dY
dX
y dY
son el cambio actual relativo al componente de view
seleccionado, donde:
- -1.0f es un deslizamiento completo de derecha a izquierda (de
ItemTouchHelper.END
a ItemTouchHelper.START
) - 1.0f se desliza por completo de izquierda a derecha (desde
ItemTouchHelper.START
a ItemTouchHelper.END
)
Es importante llamar a super
para cualquier actionState
que no esté procesando para activar la animación predeterminada.
En la siguiente parte, consideraremos un ejemplo en el que controlaremos el dibujo de un elemento en el momento de arrastrar y soltar.
Conclusión
De hecho, configurar ItemTouchHelper es bastante divertido. Para no aumentar el volumen de este artículo, lo dividí en varios.
Código fuente
Consulte el código completo de esta serie de artículos en los repositorios de Android-ItemTouchHelper-Demo GitHub. Este artículo cubre las confirmaciones de ef8f149 a d164fba .
← Arrastra y desliza en RecyclerView. Parte 1: ItemTouchHelper