Android RecyclerView et Android CardView ont été introduits dans Android Lollipop avec Material Design. Pour ceux qui ne connaissent pas le Material Design, il s’agit d’un guide complet des widgets UI introduits depuis Android 5.0 et il améliore l’attrait visuel des applications.
Android RecyclerView
Android RecyclerView est une version plus avancée, puissante et flexible du ListView. Android RecyclerView est similaire au ListView sauf qu’il nous oblige à utiliser la classe RecyclerView.ViewHolder pour contenir les éléments, ce qui n’est pas une obligation dans ListView. Comme son nom l’indique, Android RecyclerView est utilisé pour réutiliser les cellules lors du défilement vers le haut et vers le bas en recyclant les éléments de la liste. Une autre amélioration de RecyclerView est qu’il nous permet de définir les LayoutManagers dynamiquement à l’exécution, contrairement au ListView qui était uniquement disponible dans une liste déroulante verticale. RecyclerView nous permet de définir les types de mises en page suivants à l’exécution.
- LinearLayoutManager : prend en charge à la fois les listes verticales et horizontales
- StaggeredLayoutManager : il prend en charge les listes décalées
- GridLayoutManager : il prend en charge l’affichage des grilles telles qu’on les voit dans GalleryView plus tôt
Classes Android RecyclerView
- La classe RecyclerView.ItemAnimator fournit un meilleur support pour l’animation des vues contrairement aux ListViews
- La classe RecyclerView.ItemDecorator fournit un meilleur support lorsqu’il s’agit d’ajouter des bordures et des séparateurs, donnant ainsi un grand contrôle à l’utilisateur
Par conséquent, un RecyclerView est plus personnalisable par rapport à ListView et donne un plus grand contrôle aux utilisateurs. Le RecyclerView est disponible dans la bibliothèque de support. Nous devons donc modifier notre script gradle pour ajouter la dépendance suivante.
dependencies {
compile 'com.android.support:recyclerview-v7:21.0.0-rc1'
}
CardView Android
Le composant d’interface utilisateur CardView Android affiche des informations à l’intérieur de cartes. Ce composant est généralement utilisé pour afficher des informations de contact. Ce composant est disponible dans une autre bibliothèque de support, nous devons donc également ajouter sa dépendance.
dependencies {
compile 'com.android.support:cardview-v7:21.0.0-rc1'
compile 'com.android.support:recyclerview-v7:21.0.0-rc1'
}
Le widget CardView d’Android nous permet de contrôler la couleur de fond, l’ombre, le rayon des coins, l’élévation, etc. Pour utiliser les attributs personnalisés dans XML, nous devons ajouter la déclaration d’espace de noms suivante à la mise en page parente. Voici la déclaration d’espace de noms avec certains attributs de notre projet.
<android.support.v7.widget.CardView
android:id="@+id/card_view"
xmlns:card_view="https://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardBackgroundColor="@color/grey_300"
card_view:cardCornerRadius="10dp"
card_view:cardElevation="5dp"
card_view:cardUseCompatPadding="true">
Les attributs importants utilisés ci-dessus sont :
- card_view:cardCornerRadius : Utilisé pour définir le rayon des coins dans nos mises en page
- card_view:cardBackgroundColor : Utilisé pour définir la couleur de fond de la vue
Dans notre projet d’exemple, nous ajouterons un RecyclerView pour afficher une liste de CardViews contenant des noms et des numéros de version d’Android ainsi qu’un logo d’exemple. Le onclick
de CardView est programmé pour supprimer cette carte de la liste. Nous avons ajouté une option de menu dans l’ActionBar pour réintégrer les cartes supprimées dans l’ordre. Remarque : Les images de logo sont prises au hasard sur Google. Les tailles peuvent donc varier.
Exemple de RecyclerView et CardView d’Android
Le projet consiste en une
MainActivity
qui affiche le RecyclerView
. Le CardView est ajouté au RecyclerView à partir de la classe CustomAdapter. Le DataModel est utilisé pour récupérer les données de chaque CardView via des getters. La classe MyData contient les tableaux de textviews et de drawables ainsi que leurs identifiants.
Exemple de code Android RecyclerView et CardView
Le fichier activity_main.xml
contient le RecyclerView à l’intérieur d’un RelativeLayout comme indiqué ci-dessous. Code de activity_main.xml :
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity"
android:background="@color/grey_300"
>
<android.support.v7.widget.RecyclerView
android:id="@+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
/>
</RelativeLayout>
La mise en page de la CardView Android est définie ci-dessous : code de cards_layout.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:tag="cards main container">
<android.support.v7.widget.CardView
android:id="@+id/card_view"
xmlns:card_view="https://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardBackgroundColor="@color/color_white"
card_view:cardCornerRadius="10dp"
card_view:cardElevation="5dp"
card_view:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<ImageView
android:id="@+id/imageView"
android:tag="image_tag"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_weight="1"
android:src="@drawable/ic_launcher"/>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_weight="2"
android:orientation="vertical"
>
<TextView
android:id="@+id/textViewName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
android:text="Android Name"
android:textAppearance="?android:attr/textAppearanceLarge"/>
<TextView
android:id="@+id/textViewVersion"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
android:text="Android Version"
android:textAppearance="?android:attr/textAppearanceMedium"/>
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
La CardView Android contient une ImageView ainsi que deux TextViews dans un Layout linéaire imbriqué. Le fichier menu_main.xml
contient un seul élément pour ajouter les cartes supprimées. Code de menu_main.xml :
<menu xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
tools:context=".MainActivity">
<item android:id="@+id/add_item"
android:title="Add"
android:orderInCategory="100"
app:showAsAction="always"/>
</menu>
La classe MainActivity.java
est définie ci-dessous :
package com.journaldev.recyclerviewcardview;
import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private static RecyclerView.Adapter adapter;
private RecyclerView.LayoutManager layoutManager;
private static RecyclerView recyclerView;
private static ArrayList data;
static View.OnClickListener myOnClickListener;
private static ArrayList removedItems;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myOnClickListener = new MyOnClickListener(this);
recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
data = new ArrayList();
for (int i = 0; i < MyData.nameArray.length; i++) {
data.add(new DataModel(
MyData.nameArray[i],
MyData.versionArray[i],
MyData.id_[i],
MyData.drawableArray[i]
));
}
removedItems = new ArrayList();
adapter = new CustomAdapter(data);
recyclerView.setAdapter(adapter);
}
private static class MyOnClickListener implements View.OnClickListener {
private final Context context;
private MyOnClickListener(Context context) {
this.context = context;
}
@Override
public void onClick(View v) {
removeItem(v);
}
private void removeItem(View v) {
int selectedItemPosition = recyclerView.getChildPosition(v);
RecyclerView.ViewHolder viewHolder
= recyclerView.findViewHolderForPosition(selectedItemPosition);
TextView textViewName
= (TextView) viewHolder.itemView.findViewById(R.id.textViewName);
String selectedName = (String) textViewName.getText();
int selectedItemId = -1;
for (int i = 0; i < MyData.nameArray.length; i++) {
if (selectedName.equals(MyData.nameArray[i])) {
selectedItemId = MyData.id_[i];
}
}
removedItems.add(selectedItemId);
data.remove(selectedItemPosition);
adapter.notifyItemRemoved(selectedItemPosition);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
if (item.getItemId() == R.id.add_item) {
// Vérifiez s'il y a des éléments à ajouter
if (removedItems.size() != 0) {
addRemovedItemToList();
} else {
Toast.makeText(this, "Nothing to add", Toast.LENGTH_SHORT).show();
}
}
return true;
}
private void addRemovedItemToList() {
int addItemAtListPosition = 3;
data.add(addItemAtListPosition, new DataModel(
MyData.nameArray[removedItems.get(0)],
MyData.versionArray[removedItems.get(0)],
MyData.id_[removedItems.get(0)],
MyData.drawableArray[removedItems.get(0)]
));
adapter.notifyItemInserted(addItemAtListPosition);
removedItems.remove(0);
}
}
La méthode removeItems()
est invoquée depuis la méthode auditrice pour supprimer la CardView cliquée. Son identifiant respectif est stocké dans un tableau pour le récupérer ultérieurement. Pour ajouter la vue plus tard, nous avons implémenté une autre méthode nommée addRemovedItemToList()
. Dans cette méthode, nous ajoutons cette vue à une position prédéfinie dans la liste et supprimons son identifiant du tableau removedItems
. Le CustomAdapter est notifié dans les deux cas. La classe CustomeAdapter.java est définie ci-dessous :
package com.journaldev.recyclerviewcardview;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.MyViewHolder> {
private ArrayList<DataModel> dataSet;
public static class MyViewHolder extends RecyclerView.ViewHolder {
TextView textViewName;
TextView textViewVersion;
ImageView imageViewIcon;
public MyViewHolder(View itemView) {
super(itemView);
this.textViewName = (TextView) itemView.findViewById(R.id.textViewName);
this.textViewVersion = (TextView) itemView.findViewById(R.id.textViewVersion);
this.imageViewIcon = (ImageView) itemView.findViewById(R.id.imageView);
}
}
public CustomAdapter(ArrayList<DataModel> data) {
this.dataSet = data;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.cards_layout, parent, false);
view.setOnClickListener(MainActivity.myOnClickListener);
MyViewHolder myViewHolder = new MyViewHolder(view);
return myViewHolder;
}
@Override
public void onBindViewHolder(final MyViewHolder holder, final int listPosition) {
TextView textViewName = holder.textViewName;
TextView textViewVersion = holder.textViewVersion;
ImageView imageView = holder.imageViewIcon;
textViewName.setText(dataSet.get(listPosition).getName());
textViewVersion.setText(dataSet.get(listPosition).getVersion());
imageView.setImageResource(dataSet.get(listPosition).getImage());
}
@Override
public int getItemCount() {
return dataSet.size();
}
}
Dans le code ci-dessus, nous avons implémenté notre propre ViewHolder en étendant RecyclerView.ViewHolder. La vue est gonflée depuis le fichier cards_layout.xml
que nous avions défini dans le répertoire des mises en page. Le onClickListener dans MainActivity est attaché à cette vue dans le snippet ci-dessous.
view.setOnClickListener(MainActivity.myOnClickListener);
Un ArrayList stocke toutes les données sous forme d’objet de classe DataModel dans un ArrayList et les ajoute aux cartes respectives dans la liste. Les classes DataModel.java
et MyData.java
qui contiennent les données spécifiques à cette application sont données ci-dessous :
package com.journaldev.recyclerviewcardview;
public class DataModel {
String name;
String version;
int id_;
int image;
public DataModel(String name, String version, int id_, int image) {
this.name = name;
this.version = version;
this.id_ = id_;
this.image=image;
}
public String getName() {
return name;
}
public String getVersion() {
return version;
}
public int getImage() {
return image;
}
public int getId() {
return id_;
}
}
package com.journaldev.recyclerviewcardview;
public class MyData {
static String[] nameArray = {"Cupcake", "Donut", "Eclair", "Froyo", "Gingerbread", "Honeycomb", "Ice Cream Sandwich","JellyBean", "Kitkat", "Lollipop", "Marshmallow"};
static String[] versionArray = {"1.5", "1.6", "2.0-2.1", "2.2-2.2.3", "2.3-2.3.7", "3.0-3.2.6", "4.0-4.0.4", "4.1-4.3.1", "4.4-4.4.4", "5.0-5.1.1","6.0-6.0.1"};
static Integer[] drawableArray = {R.drawable.cupcake, R.drawable.donut, R.drawable.eclair,
R.drawable.froyo, R.drawable.gingerbread, R.drawable.honeycomb, R.drawable.ics,
R.drawable.jellybean, R.drawable.kitkat, R.drawable.lollipop,R.drawable.marsh};
static Integer[] id_ = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
}
Voici la sortie produite par notre application exemple Android RecyclerView et CardView. Comme vous pouvez le voir, l’élément supprimé est toujours ajouté au troisième indice (quatrième position dans la liste). Cela marque la fin de ce tutoriel sur RecyclerView et CardView Android. Vous pouvez télécharger le Projet Exemple Android RecyclerView CardView depuis le lien ci-dessous.