Ordinateurs

Comment activer le balayage pour les actions dans Android RecyclerView

Mohammad Yasir est diplômé en physique de l’Université de Delhi et actuellement inscrit au programme de maîtrise à l’IIT.

glisser-android-recyclerview

RecyclerView est l’une des classes les plus incroyables et les plus polyvalentes du SDK Android qui peut servir d’alternative moderne et économe en mémoire aux instances ListView et GridView.

Dans cet article, nous discuterons d’un moyen simple et rapide d’implémenter la fonctionnalité de balayage dans vos applications Android qui utilisent la classe RecyclerView. Bien qu’une application de base de la classe RecyclerView soit assez rudimentaire, cet article suppose que vous avez une compréhension fondamentale du développement d’applications Android à l’aide de Java et que vous êtes à l’aise avec RecyclerViews.

Ce que nous essayons de réaliser

En soi, la classe RecyclerView n’est rien de plus qu’un module dans lequel vos instances ViewHolder peuvent résider. Il ne peut gérer aucune autre charge de travail. Bien que cela ait un sens à plusieurs égards, cela signifie également que plusieurs fonctionnalités de base manquent par défaut dans RecyclerView.

Heureusement, l’introduction des classes ItemTouchHelper et SimpleCallback vous permet d’implémenter rapidement cette fonctionnalité assez facilement. Voici ce dont je parle, magnifiquement implémenté par Microsoft Outlook :

MS Outlook offre une option permettant de balayer pour une action rapide sur vos e-mails.

MS Outlook offre une option permettant de balayer pour une action rapide sur vos e-mails.

Comment faisons-nous pour que cela se produise ?

La nature open source du système d’exploitation Android et sa popularité illimitée lui confèrent un avantage significatif sur ses concurrents en termes de flexibilité et de polyvalence. À l’origine, l’idée était de choisir une bibliothèque open source de GitHub qui incluait ces fonctionnalités dans une classe RecyclerView personnalisée. Cependant, cette méthode est désormais obsolète.

Les classes ItemTouchHelper et SimpleCallback, comme mentionné précédemment, fournissent quelques méthodes que nous pouvons remplacer et implémenter des gestes complexes de balayage et de glisser-déposer dans nos instances RecyclerView. C’est ce que nous allons faire dans cet article. La capture d’écran ci-dessous montre à quoi ressemblera le résultat final :

Le résultat final : glisser vers la droite

A lire aussi :  Meilleur ordinateur portable pour la programmation - Trouvez la machine parfaite pour vos besoins de codage

Le résultat final : glisser vers la droite

Le processus

Le moyen le plus simple et le plus rapide d’inclure la fonctionnalité de balayage dans vos instances RecyclerView consiste à étendre la classe SimpleCallback, à remplacer les méthodes getSwipeDirs(), onMove() et onChildDrawOver() et à effectuer les étapes suivantes :

  • Dans la méthode getSwipeDirs(), renvoyez soit 0 pour empêcher un utilisateur de balayer, par exemple, une vue enfant utilisée comme en-tête, soit renvoyez avec un appel à super.getSwipeDirs().
  • Dans la méthode onMove(), retournez un booléen valeur indiquant si vous souhaitez activer le déplacement de l’élément RecyclerView. Je suis revenu faux et vous devrez écrire votre propre implémentation si votre cas implique également de faire glisser.
  • Écrivez la logique pour dessiner l’arrière-plan et l’icône de balayage dans onChildDrawOver().

Une fois que vous avez effectué les étapes susmentionnées, nous verrons comment utiliser une instance de la classe que vous avez créée.

Commençons

Commencez par créer une nouvelle classe Java dans votre projet et nommez-la RecyclerSwipeHelper.java. Cette classe étendra SimpleCallback et remplacera son constructeur, ainsi que les trois méthodes que j’ai mentionnées ci-dessus.

La première étape consiste à créer quelques variables globales qui vous seront utiles plus tard. Jetez un oeil ci-dessous:

//You can set this tag in your adapter's onAttachViewHolder() method if you wish to prevent swiping on a particular child view. Then use an if condition in the getSwipeDirs() method and return 0 if the tag equals @link TAG_NO_SWIPE
public static final String TAG_NO_SWIPE = "don't swipe this item";
    
private final int intrinsicWidth;
private final int intrinsicHeight;
private final int swipeLeftColor;
private final int swipeRightColor;

private final Paint clearPaint;
private final Drawable swipeRightIcon;
private final Drawable swipeLeftIcon;
private final ColorDrawable background = new ColorDrawable();

Le Constructeur

public RecyclerSwipeHelper(@ColorInt int swipeRightColor, @ColorInt int swipeLeftColor, @DrawableRes int swipeRightIconResource, @DrawableRes int swipeLeftIconResource, Context context) {

	//The LEFT|RIGHT are tags from the ItemTouchHelper class that inform the system about swipe directions. The first paramter informs the system about dragging directions, which are 0 to prevent dragging.
	super(0, LEFT|RIGHT);
	
	//here, you can initialize the icons that will be displayed upon swiping. That is what the parameters are for. You can customize them as per your needs. As an example, here is the swipeRightIcon initialized using the ContextCompat class.
	//You can similarly initialize swipeLeftIcon. 
	this.swipeRightIcon = ContextCompat.getDrawable(context, swipeRightIconResource);

	//initialize a few global variables for later use.
	//the Paint instance will be used to clear the canvas if the swiping is canceled by the user.
	clearPaint = new Paint();
	clearPaint.setXfermode(new PorterDuffXfermode(CLEAR));

	// these are int parameters and represent the intrinsic height and width of your icons. These icons are aptly named swipeRightIcon and swipeLeftIcon. 
	intrinsicHeight = swipeRightIcon.getIntrinsicHeight();
	intrinsicWidth = swipeRightIcon.getIntrinsicWidth();
}

Le cerveau de l’opération

La méthode onChildDrawOver() est l’endroit où toute la magie opère. Dans cette méthode, vous effectuerez les étapes suivantes :

A lire aussi :  Utilisation de la recherche pour trouver des livres, des DVD et des CD à la maison

Faites défiler pour continuer

  1. Obtenez la hauteur de la vue enfant à l’aide du ViewHolder fourni dans les paramètres.
  2. Vérifiez si le balayage a été annulé par l’utilisateur. Si oui, videz la toile, appelez superet revenir.
  3. Sinon, vérifiez si le balayage a été effectué vers la droite ou vers la gauche. De manière appropriée, dessinez l’icône et l’arrière-plan corrects.

Voici comment nous y parvenons :

//get item height and check if cancelled
View itemView = viewHolder.itemView;
int itemHeight = itemView.getBottom() - itemView.getTop();
boolean isCanceled = (dX == 0f) && !isCurrentlyActive;

if (isCanceled) {
	clearCanvas(c, itemView.getRight() + dX, itemView.getTop(), itemView.getRight(), itemView.getBottom());
	super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, false);
	return;
}

if (dX < 0); //swipe left logic;
else; //swipe right logic

Alors que le code ci-dessus est assez explicite, vous remarquerez une méthode étrange qui est appelée dans le cas où la variable isCanceled est évaluée comme étant vrai.

Il est absolument essentiel que vous appeliez cette méthode car elle effacera notre canevas et affichera l'élément RecyclerView d'origine. C'est ainsi que vous y arriverez. Remarquez comment nous avons utilisé l'instance clearPaint que nous avons créée au début pour effacer tous les signes des icônes ou des arrière-plans qui auraient pu être dessinés avant l'annulation du balayage :

private void clearCanvas(Canvas c, float left, float top, float right, float bottom) {
	if(c != null) c.drawRect(left, top, right, bottom, clearPaint);
}

Dessiner les icônes et les arrière-plans

Par défaut, la classe ItemTouchHelper ne fera rien d'autre que glisser votre ViewHolder dans la direction autorisée. Vous devrez gérer vous-même le dessin de l'arrière-plan et des icônes. Quelle que soit la direction, la logique derrière cela est assez similaire.

  1. Dessinez la couleur d'arrière-plan en utilisant le ColorDrawable que nous avons initialisé au début.
  2. Calculez la position du drawable. La logique changera légèrement avec la direction.
  3. Dessinez l'icône.

Jetez un oeil ci-dessous:

//This sample is for the swipe left logic, i.e. it will go into the if block of your code. 

background.setColor(swipeLeftColor);
background.setBounds((int) (itemView.getRight() + dX), itemView.getTop(), itemView.getRight(), itemView.getBottom());
background.draw(c);

int itemTop = itemView.getTop() + (itemHeight - intrinsicHeight) / 2;
int itemMargin = (itemHeight - intrinsicHeight) / 2;
int itemLeft = itemView.getRight() - itemMargin - intrinsicWidth;
int itemRight = itemView.getRight() - itemMargin;
int itemBottom = itemTop + intrinsicHeight;

swipeLeftIcon.setBounds(itemLeft, itemTop, itemRight, itemBottom);
swipeLeftIcon.draw(c);

Encore une fois, vous pouvez voir à quel point il est simple de dessiner les icônes. Notez que puisque nous utilisons un canevas pour dessiner l'icône directement, nous devrons calculer ses attributs gauche, droite, haut et bas. Ils serviront à placer correctement le drawable.

A lire aussi :  8 meilleures animations de particules JavaScript à ajouter à votre site

Qu'en est-il du balayage vers la droite ?

facile. Faites juste quelques ajustements comme indiqué ci-dessous:

background.setColor(swipeRightColor);

//Notice how we are using the getLeft() method here instead of getRight().
background.setBounds((int) (itemView.getLeft() + dX), itemView.getTop(), itemView.getLeft(), itemView.getBottom());
background.draw(c);

int itemTop = itemView.getTop() + (itemHeight - intrinsicHeight) / 2;
int itemMargin = (itemHeight - intrinsicHeight) / 2;
int itemLeft = itemView.getLeft() + itemMargin;
int itemRight = itemView.getLeft() + itemMargin + intrinsicWidth;
int itemBottom = itemTop + intrinsicHeight;

swipeRightIcon.setBounds(itemLeft, itemTop, itemRight, itemBottom);
swipeRightIcon.draw(c);

Remarquez comment les limites de l'arrière-plan ainsi que la logique à calculer élémentGauche et élémentDroit a changé. Sans cela, l'icône serait dessinée dans des endroits étranges et finirait même par être invisible.

REMARQUE:

N'oubliez pas d'appeler super une fois votre logique terminée, comme indiqué ci-dessous :

super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);

Finir

Et c'est tout! Avant que vous ne vous en rendiez compte, votre classe RecyclerSwipeHelper est terminée et vous êtes prêt à l'utiliser et à balayer. Vous remarquerez à nouveau la facilité remarquable avec laquelle vous pouvez y arriver. Jetez un oeil à l'exemple ci-dessous:

RecyclerSwipeHelper mRecyclerSwipeHelper = new RecyclerSwipeHelper(swipeRightColor, swipeLeftColor, swipeRightIconResource, swipeLeftIconResource, context) {
	@Override
	public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
		
		//calling the notifyItemChanged() method is absolutely essential to redraw the RecyclerView item and remove the icons we had drawn.
		mAdapter.notifyItemChanged(viewHolder.getBindingAdapterPosition());

		if (direction == ItemTouchHelper.LEFT)
		//handle left swipe
		
		else 
		//handle right swipe
      
    	}
};
ItemTouchHelper mItemTouchHelper = new ItemTouchHelper(mRecyclerSwipeHelper);
mItemTouchHelper.attachToRecyclerView(mRecyclerView);

Exemple de code complet

Le RecyclerSwipeHelper que j'utilise pour mes projets est disponible sur mon GitHub gist. Vous pouvez l'importer directement dans votre projet si vous ne voulez pas créer votre propre implémentation.

Psst ! Si vous importez ma classe dans votre projet, vous pourrez mettre la main sur une animation de fondu enchaîné et de fondu enchaîné sur vos icônes tout en glissant. N'oubliez pas de me créditer si vous le faites, comme mentionné ci-dessous :

RecyclerSwipeHelper a été créé par Mohammad Yasir.

Laissez vos précieux commentaires et partagez tous les conseils que vous jugez utiles.

© 2021 Mohamed Yasir

Bouton retour en haut de la page