
Dans la première partie, nous avons examiné ItemTouchHelper et l'implémentation de ItemTouchHelper.Callback , qui ajoute les fonctions de base de glisser-déposer et de glisser- déplacer pour ignorer RecyclerView
. Dans cet article, nous continuerons ce qui a été fait dans le précédent en ajoutant la prise en charge de l'organisation des éléments sous forme de grille, des contrôleurs de glisser-déposer, la sélection d'un élément de liste et des animations de balayage personnalisées.

Contrôleurs de glisser-déposer
Lors de la création d'une liste qui prend en charge le glisser-déposer , ils implémentent généralement la possibilité de glisser-déposer des éléments au toucher. Cela contribue à la clarté et à la facilité d'utilisation de la liste en "mode édition", et est également recommandé par les directives matérielles. Ajouter des contrôleurs de glisser-déposer à notre exemple est incroyablement facile.

Tout d'abord, mettez à jour la layout
élément ( 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>
L'image utilisée pour le contrôleur de glissement peut être trouvée dans les icônes Material Design et ajoutée au projet à l'aide du plugin générateur d'icônes pratique dans Android Studio.
Comme brièvement mentionné dans un article précédent, vous pouvez utiliser ItemTouchHelper.startDrag(ViewHolder)
pour démarrer par programme un glisser-déposer. Donc, tout ce que nous devons faire est de mettre à jour le ViewHolder
en ajoutant un contrôleur de glisser et configurer un gestionnaire tactile simple qui appellera startDrag()
.
Nous aurons besoin d'une interface pour transmettre les événements le long de la chaîne:
public interface OnStartDragListener { void onStartDrag(RecyclerView.ViewHolder viewHolder); }
Définissez ensuite une ImageView
pour le contrôleur de glissement dans le ItemViewHolder
:
public final ImageView handleView; public ItemViewHolder(View itemView) { super(itemView);
et mettez à jour RecyclerListAdapter
:
private final OnStartDragListener mDragStartListener; public RecyclerListAdapter(OnStartDragListener dragStartListener) { mDragStartListener = dragStartListener;
RecyclerListAdapter
devrait maintenant ressembler à ceci .
Tout ce qui reste à faire est d'ajouter le OnStartDragListener
au fragment:
public class RecyclerListFragment extends Fragment implements OnStartDragListener {
RecyclerListFragment
devrait maintenant ressembler à ceci . Maintenant, lorsque vous lancez l'application, vous pouvez commencer à glisser-déposer en touchant le contrôleur.

Mettre en surbrillance un élément de liste
Maintenant, dans notre exemple, il n'y a aucune indication visuelle de l'élément que vous faites glisser. Évidemment, cela ne devrait pas être le cas, mais c'est facile à corriger. À l'aide d' ItemTouchHelper
vous pouvez utiliser des effets de surbrillance d'élément standard. Sur Lollipop et les versions ultérieures d'Android, le rétro-éclairage "se propage" sur l'élément dans le processus d'interaction avec lui; sur les versions antérieures, l'élément change simplement de couleur pour s'assombrir.
Pour implémenter cela dans notre exemple, ajoutez simplement un arrière-plan (propriété background
) à FrameLayout
racine FrameLayout
élément FrameLayout
ou définissez-le dans le constructeur de RecyclerListAdapter.ItemViewHolder . Cela ressemblera à ceci:

Ça a l'air cool, mais vous voudrez peut-être contrôler encore plus. Une façon de procéder consiste à autoriser ViewHolder
gérer les changements d'état d'un élément. Pour cela, ItemTouchHelper.Callback
propose deux autres méthodes:
onSelectedChanged(ViewHolder, int)
est appelé à chaque fois que l'état d'un élément change pour glisser ( ACTION_STATE_DRAG ) ou glisser ( ACTION_STATE_SWIPE ). C'est un endroit idéal pour changer l'état du composant de view
en actif .clearView(RecyclerView, ViewHolder)
est appelé lorsque le composant de view
glisser-déplacer est terminé, ainsi que lorsque le balayage est terminé ( ACTION_STATE_IDLE ). Ici, l'état initial de votre composant de view
est généralement restauré.
Maintenant, mettons tout cela ensemble.
Tout d'abord, créez une interface que ViewHolders
implémentera:
public interface ItemTouchHelperViewHolder { void onItemSelected(); void onItemClear(); }
Ensuite, dans SimpleItemTouchHelperCallback
implémentez les méthodes appropriées:
@Override public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
Maintenant, tout ce qui reste à faire est que RecyclerListAdapter.ItemViewHolder
implémente ItemTouchHelperViewHolder
:
public class ItemViewHolder extends RecyclerView.ViewHolder implements ItemTouchHelperViewHolder {
Dans cet exemple, nous ajoutons simplement un arrière-plan gris pendant que l'élément est actif, puis le supprimons. Si votre ItemTouchHelper
et votre adaptateur sont étroitement connectés, vous pouvez facilement abandonner ce paramètre et changer l'état du composant de view
directement dans ItemTouchHelper.Callback
.
Filets
Si maintenant vous essayez d'utiliser le GridLayoutManager
, vous verrez qu'il ne fonctionne pas correctement. La raison et la solution sont simples: nous devons dire à notre ItemTouchHelper
que nous voulons prendre en charge le déplacement des éléments vers la gauche et la droite. Plus tôt dans SimpleItemTouchHelperCallback
nous avons déjà spécifié:
@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); }
La seule modification nécessaire pour prendre en charge les grilles consiste à ajouter les indicateurs appropriés:
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
Cependant, le glissement vers la suppression n'est pas un comportement très naturel pour les éléments de grille, donc les swipeFlags
plus susceptibles d'être 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); }
Pour voir un exemple de GridLayoutManager
fonctionnel, voir RecyclerGridFragment . Voici à quoi cela ressemble au démarrage:

Animations de balayage personnalisées
ItemTouchHelper.Callback
fournit un moyen très pratique de contrôler entièrement l'animation tout en faisant glisser ou en balayant. Puisque ItemTouchHelper
est un RecyclerView.ItemDecoration , nous pouvons intervenir dans le processus de rendu d'un composant de view
d'une manière similaire. Dans la partie suivante, nous examinerons cette question plus en détail, mais pour l'instant, regardons un exemple simple de remplacement de l'animation de balayage par défaut pour montrer une disparition linéaire.
@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); } }
Les dY
dX
et dY
sont le décalage actuel par rapport au composant de view
sélectionné, où:
- -1.0f est un balayage complet de droite à gauche (de
ItemTouchHelper.END
à ItemTouchHelper.START
) - 1.0f est un balayage complet de gauche à droite (de
ItemTouchHelper.START
à ItemTouchHelper.END
)
Il est important d'appeler super
pour toute actionState
que vous ne traitez pas afin de déclencher l'animation par défaut.
Dans la partie suivante, nous considérerons un exemple dans lequel nous contrôlerons le dessin d'un élément au moment du glisser-déposer.
Conclusion
En fait, configurer ItemTouchHelper est assez amusant. Afin de ne pas augmenter le volume de cet article, je l'ai divisé en plusieurs.
Code source
Voir le code complet de cette série d'articles sur les référentiels GitHub Android-ItemTouchHelper-Demo . Cet article couvre les validations de ef8f149 à d164fba .
← Faites glisser et faites glisser dans RecyclerView. Partie 1: ItemTouchHelper