La Boîte à Outils Android Widget

 Android fournit une boîte à outils de vues standard pour vous aider à créer vos interfaces utilisateur. En utilisant ces contrôles (et en les modifiant ou en les développant au besoin), vous pouvez simplifier votre développement et assurer la cohérence entre les applications et avec l'interface utilisateur du système Android. La liste suivante présente certaines des commandes les plus courantes:

  • TextView : étiquette de texte standard en lecture seule prenant en charge l'affichage multiligne, le formatage de chaîne et le retour à la ligne automatique.
  • EditText : une zone de saisie de texte modifiable qui accepte les saisies multilignes, le retour à la ligne et le texte d'indice.
  • ImageView - Une vue qui montre une seule image.Bar Barre d'outils: vue affichant un titre et des actions communes, souvent utilisée comme barre d'applications principale en haut d'une activité.
  • ProgressBar : une vue qui présente un indicateur de progression indéterminé (un cercle en rotation) ou une barre de progression horizontale.
  • RecyclerView : groupe de vues qui gère l'affichage d'un grand nombre de vues dans un conteneur avec défilement. Prend en charge un certain nombre de gestionnaires de disposition qui vous permettent de disposer des vues sous forme de liste verticale et horizontale ou de grille.
  • Bouton — Un bouton-poussoir interactif standard.
  • ImageButton : bouton-poussoir pour lequel vous pouvez spécifier une image d'arrière-plan personnalisée.
  • CheckBox : un bouton à deux états représenté par une case à cocher ou à cocher.
  • RadioButton : un bouton groupé à deux états. Un groupe de ceux-ci présente à l'utilisateur un certain nombre d'options possibles, dont une seule peut être activée à la fois.
  • VideoView : gère la gestion de tous les états et la configuration de la surface d'affichage pour lire des vidéos plus simplement à partir de votre activité.
  • ViewPager : implémente un ensemble de vues défilant horizontalement. Le View Pager permet aux utilisateursglisser ou glisser vers la gauche ou la droite pour basculer entre différentes vues. Ceci n'est qu'une sélection des widgets disponibles. Android prend également en charge plusieurs implémentations View plus avancées, notamment les sélecteurs de date et d'heure et les zones de saisie semi-automatique. 

 Travailler avec les listes et les grilles

Lorsque vous devez afficher un grand ensemble de données dans votre interface utilisateur, il peut être tentant d’ajouter des centaines de

Vues sur votre interface utilisateur. C'est presque toujours la mauvaise approche. RecyclerView (disponible dans la bibliothèque de support Android) propose plutôt un groupe de vues à défilement spécialement conçu pour afficher et faire défiler efficacement un grand nombre d'éléments.

La vue Recycler peut être utilisée dans les orientations verticale et horizontale, configurée à l'aide de l'attribut android: orientation:

< android.support.v7.widget.RecyclerView

  xmlns:android:"http://schemas.android.com/apk/res/android"   xmlns:app="http://schemas.android.com/apk/res-auto"

  android:id="@+id/recycler_view"   android:layout_width="match_parent"   android:layout_height="match_parent"   android:orientation="vertical"

  [... Layout Manager Attributes ...]

/>

Dans une orientation verticale, les éléments sont disposés de haut en bas et la vue Recycleur défile verticalement, tandis qu'une orientation horizontale les disposera de gauche à droite et la vue Recycleur défilera horizontalement.

 Gestionnaires de vue et de mise en page du recycleur

 RecyclerView lui-même ne contrôle pas la façon dont chaque élément est affiché; cette responsabilité appartient à RecyclerView.LayoutManager associé. Cette séparation des tâches vous permet de remplacer les classes du gestionnaire de disposition sans affecter d’autres parties de votre application.

Un certain nombre de gestionnaires de disposition sont disponibles, comme illustré à la figure 5-4 et décrits ici:

  • LinearLayoutManager : affiche les éléments dans une seule liste verticale ou horizontale.
  • GridLayoutManager : similaire au gestionnaire de disposition linéaire, mais affiche une grille. Lorsqu'elles sont disposées verticalement, chaque ligne peut inclure plusieurs éléments, chacun ayant la même hauteur. Pour une orientation horizontale, chaque élément d'une colonne donnée doit avoir la même largeur.
  • StaggeredGridLayoutManager : similaire au gestionnaire d’agencement de la grille, mais crée une «grille», où chaque cellule de la grille peut avoir une hauteur ou une largeur différente, les cellules étant décalées pour éliminer les espaces vides.

 Le gestionnaire de disposition fonctionne de la même manière qu'une disposition standard: elle est responsable de la disposition des vues représentant chaque élément de votre jeu de données.

La vue Recycler tire son nom de la façon dont elle prend en charge le défilement. Plutôt que de créer une vue pour chaque élément dès le départ, ou de les créer continuellement quand ils sont défilés, la vue Recycleur est en mesure de «recycler» les vues existantes qui ne sont plus visibles - en modifiant leur contenu et leur position pour représenter les éléments récemment visibles.

Pour prendre en charge ce problème, le gestionnaire de disposition est également chargé de déterminer le moment où une vue peut être recyclée en toute sécurité. Dans la plupart des cas, cela permet à la vue Recycleur de prendre en charge une liste presque infinie (226) d'éléments, tout en créant juste assez de vues pour remplir un seul écran.

Le gestionnaire de disposition pour une vue du recycleur peut être défini en XML ou par programme.

Par exemple, l'extrait de code suivant présente une vue de recycleur alignée verticalement avec un gestionnaire de disposition de grille comportant deux colonnes:

 < android.support.v7.widget.RecyclerView

  xmlns:android:"http://schemas.android.com/apk/res/android"   xmlns:app="http://schemas.android.com/apk/res-auto"   android:id="@+id/recycler_view"   android:layout_width="match_parent"   android:layout_height="match_parent"   android:orientation="vertical"   app:layoutManager="GridLayoutManager"

  app:spanCount="2" />

Pour attribuer le même gestionnaire de disposition dans le code, vous utiliseriez l'extrait suivant pour une vue Recycler existante:

 RecyclerView recyclerView = findViewById(R.id.recycler_view);

GridLayoutManager gridLayoutManager = new GridLayoutManager(2); recyclerView.setLayoutManager(gridLayoutManager);

 Présentation des adaptateurs

 Les gestionnaires de disposition ne sont particulièrement utiles que lorsque vous avez les données à afficher; ces données sont fournies par RecyclerView.Adapter. L'adaptateur a deux rôles importants:

  • La création initiale des vues à afficher, y compris le gonflage de la présentation appropriée
  • La création des supports de vue que vous utiliserez pour «lier» les éléments View à la source de données sous-jacente.

 Un détenteur de vue stocke la vue à afficher et permet également à l'adaptateur de stocker des métadonnées et des références de vue supplémentaires pour simplifier la liaison de données, comme indiqué ultérieurement. Cela inclut généralement la recherche de références à des vues enfant dans la présentation d'un élément (afin que le travail ne soit effectué qu'une seule fois).

La méthode onCreateViewHolder de l’adaptateur est appelée pour obtenir une nouvelle instance RecyclerView.ViewHolder chaque fois que le gestionnaire d’affichage ne dispose pas d’une vue inutilisée à réutiliser - en règle générale, il ne reste que suffisamment de vues pour remplir l’écran.

Le Listing 5-4 montre une implémentation simple d'adaptateur utilisant une seule vue de texte pour afficher des données stockées dans un tableau de chaînes.

LISTING 5-4 : Créer un adaptateur de recycleur

public class SimpleAdapter   extends RecyclerView.Adapter<SimpleAdapter.ViewHolder> {

  // Underlying data to be displayed. 

  private String[] mData; 

  // Set the initial data in the constructor   public SimpleAdapter(String[] data) {

    mData = data;

  }

  // Tell the Layout Manager how many items exist in the data

  @Override

  public int getItemCount() {

    return mData == null ? 0 : mData.length;   }

  public static class ViewHolder extends RecyclerView.ViewHolder {     public TextView textView;

    public ViewHolder(View v) {

      super(v);

      // Only do findViewById once       textView = v.findViewById(R.id.text);

    }

  }

  @Override

  public SimpleAdapter.ViewHolder onCreateViewHolder(

      ViewGroup parent, int viewType) {

    // Create the new View

    View v = LayoutInflater.from(parent.getContext())

               .inflate(R.layout.simple_text, parent, false);

    return new ViewHolder(v);   }

Notez que le détenteur de la vue n’attribue pas de valeurs des données sous-jacentes aux vues qu’il contient. Son rôle est de rendre les éléments de la présentation de la vue disponibles pour que l’adaptateur puisse y lier des données.

À chaque fois qu'un élément doit être affiché, le Gestionnaire de mise en page appelle la méthode onBindViewHolder de l'adaptateur, en vous fournissant un ViewHolder créé précédemment et la position demandée dans le jeu de données. Cette phase de liaison est très fréquente lors du défilement d'une liste (une fois pour chaque élément défilant dans la vue), elle doit donc être aussi légère que possible.

@Override

public void onBindViewHolder(ViewHolder holder, int position) {

  holder.textView.setText(mData[position]); }

Remarque Lors de la liaison d’un nouvel élément de données, il est important de réinitialiser tout élément View précédemment défini. Etant donné que le titulaire de la vue (et ses éléments de vue) sont constamment réutilisés, ils conservent tous les états définis lors d'appels précédents onBindViewHolder.

 Pour affecter votre adaptateur à une vue du recycleur, utilisez la méthode setAdapter:

 RecyclerView recyclerView = findViewById(R.id.recycler_view);

SimpleAdapter adapter =   new SimpleAdapter(new String[] {"Sample", "Sample 2"}); recyclerView.setAdapter(adapter);

 Les jeux de données statiques tels que cet exemple sont amusants, mais en réalité, nous sommes rarement aussi chanceux. Dans la plupart des cas, les données sous-jacentes changent lorsque de nouvelles données sont chargées à partir du serveur, si l'utilisateur ajoute ou supprime un élément, ou même si l'ordre de tri est modifié.

Lorsque vous mettez à jour un adaptateur avec des données nouvelles ou modifiées, vous devez appeler l’une des méthodes de notification de l’adaptateur pour informer le gestionnaire de disposition que quelque chose a changé. RecyclerView animera ensuite une transition entre les états précédent et mis à jour (fondus croisés des éléments modifiés, réduction et suppression des éléments supprimés et animation de nouveaux éléments).

Vous pouvez personnaliser les animations utilisées pour chaque changement d'état en affectant un. RecyclerView .ItemAnimator à l'aide de la méthode setItemAnimator.

Il existe différentes méthodes pour notifier le changement, l'insertion, le déplacement ou la suppression d'un seul élément et pour une gamme d'éléments. Vous pouvez utiliser la classe DiffUtil pour comprendre quelles modifications doivent être appliquées pour passer d'un jeu de données à un autre, comme indiqué dans le Listing 5-5.

 LISTING 5-5: Calcul des transitions entre les jeux de données

 public class SimpleAdapter

  extends RecyclerView.Adapter<SimpleAdapter.ViewHolder> {

  [... Existing SimpleAdapter Implementation ...]

  public void setData(final String[] newData) {

    // Store a copy of the previous data     final String[] previousData = mData;

    // apply the new data     mData = newData;

    // Calculate the differences between the old and new data

    DiffUtil.calculateDiff(new DiffUtil.Callback() {

      @Override

      public int getOldListSize() {

        return previousData != null ? previousData.length : 0;       }

      @Override

      public int getNewListSize() {

        return newData != null ? previousData.length : 0;

      }           

      @Override

      public boolean areItemsTheSame(int oldItemPosition,                                      int newItemPosition) {

        // This method should compare the item's unique identifiers         // if available. Returning true means the two items should be

        // crossfaded. In this example, we don't have an identifier,

        // so we'll compare the string values.

        return TextUtils.equals(previousData[oldItemPosition],                                 newData[newItemPosition]);

      }

      @Override

      public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {  // This method should do a deep inspection of the items to determine    // if their visible contents are the same.

       // If they are the same, no animation is required.

       // In this example, if the items are the same,

       // the contents are the same

       return true;

     }

   }).dispatchUpdatesTo(this);

  }

}