Faites glisser et faites glisser dans RecyclerView. Partie 1: ItemTouchHelper

Faites glisser et faites glisser dans RecyclerView. Partie 1: ItemTouchHelper


Il existe de nombreux didacticiels, bibliothèques et implémentations de glisser- déposer et de glisser- déplacer pour supprimer dans Android à l'aide de RecyclerView. La plupart d'entre eux utilisent toujours le View.OnDragListener déconseillé et l'approche SwipeToDismiss développée par Roman Nurik. Bien que de nouvelles méthodes plus efficaces soient déjà disponibles. Très peu utilisent les dernières API, s'appuyant souvent sur GestureDetectors et onInterceptTouchEvent ou d'autres implémentations plus complexes. En fait, il existe un moyen très simple d'ajouter ces fonctions à RecyclerView . Cela ne nécessite qu'une seule classe, qui fait également partie de la bibliothèque de support Android.


ItemTouchHelper


ItemTouchHelper est un utilitaire puissant qui s'occupe de tout ce que vous devez faire pour ajouter des fonctions de glisser-déposer et de glisser- déplacer pour RecyclerView . Cet utilitaire est une sous-classe de RecyclerView.ItemDecoration , ce qui facilite son ajout à presque tous les LayoutManager et adaptateurs existants. Il fonctionne également avec l'animation d'élément et offre la possibilité de glisser-déposer des éléments d'un type vers un autre endroit de la liste et bien plus encore. Dans cet article, je vais démontrer une implémentation simple de ItemTouchHelper . Plus tard, dans le cadre de cette série d'articles, nous élargirons la portée et envisagerons d'autres options.


Remarque Vous voulez voir le résultat tout de suite? Découvrez Github: Android-ItemTouchHelper-Demo . Le premier commit concerne cet article. Le fichier de démonstration .apk peut être téléchargé ici .


Exemple


Personnalisation


Nous devons d'abord configurer le RecyclerView . Si ce n'est pas déjà fait, ajoutez la dépendance RecyclerView à votre fichier build.gradle .


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

ItemTouchHelper fonctionnera avec presque tous les RecyclerView.Adapter et LayoutManager , mais cet article est basé sur des exemples utilisant ces fichiers .


Utilisation de ItemTouchHelper et ItemTouchHelper.Callback


Pour utiliser ItemTouchHelper , vous devez créer un ItemTouchHelper.Callback . Il s'agit d'une interface qui vous permet de suivre les actions de mouvement ( eng. Move) et de glisser ( eng. Swipe). De plus, vous pouvez contrôler ici l'état du composant de view sélectionné et remplacer l'animation par défaut. Il existe une classe d'assistance que vous pouvez utiliser si vous souhaitez utiliser l'implémentation de base, SimpleCallback . Mais pour comprendre comment cela fonctionne dans la pratique, nous ferons tout par nous-mêmes.


Les principales fonctions de l'interface que nous devons redéfinir pour inclure les fonctionnalités de base du glisser-déposer et du glisser- déplacer :


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

Nous utiliserons également plusieurs méthodes d'assistance:


 isLongPressDragEnabled() isItemViewSwipeEnabled() 

Examinons-les un par un.


 @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 facilite la détermination de la direction d'un événement. Vous devez remplacer la méthode getMovementFlags() pour indiquer les directions de glisser-déposer qui seront prises en charge. Pour créer des indicateurs de retour, utilisez la méthode d'assistance ItemTouchHelper.makeMovementFlags(int, int) . Dans cet exemple, nous autorisons le glisser-déposer dans les deux sens.


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

ItemTouchHelper ne peut être utilisé que par glisser-déposer sans fonctionnalité de balayage (ou vice versa), vous devez donc spécifier exactement quelles fonctionnalités doivent être prises en charge. La méthode isLongPressDragEnabled() doit renvoyer true pour prendre en charge le glisser-déposer après un long clic sur l'élément RecyclerView . Vous pouvez également appeler la ItemTouchHelper.startDrag(RecyclerView.ViewHolder) pour commencer à faire glisser manuellement. Nous considérerons cette option plus tard.


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

Pour activer le fouet après avoir touché n'importe où dans le composant de view , renvoyez simplement true partir de la méthode isItemViewSwipeEnabled() . Vous pouvez également appeler la ItemTouchHelper.startSwipe(RecyclerView.ViewHolder) pour démarrer le balayage manuellement.


Les deux méthodes suivantes, onMove() et onSwiped() , sont requises pour vous informer des mises à jour des données. Donc, nous allons d'abord créer une interface qui permettra à ces événements de passer le long de la chaîne d'appel.


ItemTouchHelperAdapter.java


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

La façon la plus simple de procéder consiste à demander à RecyclerListAdapter d' implémenter l'écouteur.


 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; } 

Il est très important d'appeler les notifyItemRemoved() et notifyItemMoved() pour que l'adaptateur voit les modifications. Il convient également de noter que nous changeons la position de l'élément à chaque fois que la composante de view est déplacée vers un nouvel index, et non pas à la toute fin du mouvement (l'événement «drop») .


Nous pouvons maintenant revenir à la création de SimpleItemTouchHelperCallback , car nous devons toujours remplacer les onMove() et onSwiped() . Ajoutez d'abord le constructeur et le champ de l'adaptateur:


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

Redéfinissez ensuite les événements restants et signalez-les à l'adaptateur:


 @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()); } 

Par conséquent, la classe Callback devrait ressembler à ceci:


 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()); } } 

Lorsque le rappel est prêt, nous pouvons créer un ItemTouchHelper et appeler la attachToRecyclerView(RecyclerView) (par exemple, dans MainFragment.java ):


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

Après avoir commencé, vous devriez obtenir quelque chose comme ceci:


Résultat


Conclusion


Il s'agit de l'implémentation la plus simplifiée de ItemTouchHelper . Cependant, vous remarquerez peut-être que vous n'avez pas besoin d'utiliser une bibliothèque tierce pour implémenter les actions standard de glisser-déplacer et de glisser-rejeter dans RecyclerView . Dans la partie suivante, nous porterons plus d'attention à l'apparence des éléments lors du glisser-déposer.


Code source


J'ai créé un projet sur GitHub pour démontrer ce qui est couvert dans cette série d'articles: Android-ItemTouchHelper-Demo . Le premier commit concerne principalement cette partie et un peu la seconde .


→ Faites glisser et faites glisser dans RecyclerView. Partie 2: glisser-déposer des contrôleurs, des grilles et des animations personnalisées

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


All Articles