Partager via


Remplissage d’un ListView Xamarin.Android avec des données

Pour ajouter des lignes à une ListView disposition, vous devez l’ajouter à votre disposition et implémenter une IListAdapter avec des méthodes que les ListView appels doivent remplir lui-même. Android inclut des ListActivity classes intégrées que ArrayAdapter vous pouvez utiliser sans définir de code ou XML de disposition personnalisé. La ListActivity classe crée automatiquement une ListView propriété et expose une ListAdapter propriété pour fournir les vues de ligne à afficher via un adaptateur.

Les adaptateurs intégrés prennent un ID de ressource d’affichage en tant que paramètre qui est utilisé pour chaque ligne. Vous pouvez utiliser des ressources intégrées telles que celles dans Android.Resource.Layout lesquelles vous n’avez pas besoin d’écrire vos propres ressources.

Utilisation de ListActivity et arrayAdapter<String>

L’exemple BasicTable/HomeScreen.cs montre comment utiliser ces classes pour afficher une ListView seule ligne de code :

[Activity(Label = "BasicTable", MainLauncher = true, Icon = "@drawable/icon")]
public class HomeScreen : ListActivity {
   string[] items;
   protected override void OnCreate(Bundle bundle)
   {
       base.OnCreate(bundle);
       items = new string[] { "Vegetables","Fruits","Flower Buds","Legumes","Bulbs","Tubers" };
       ListAdapter = new ArrayAdapter<String>(this, Android.Resource.Layout.SimpleListItem1, items);
   }
}

Gestion des clics de ligne

En règle générale, un ListView utilisateur peut également toucher une ligne pour effectuer une action (par exemple, lire une chanson ou appeler un contact ou afficher un autre écran). Pour répondre aux touches utilisateur, il doit y avoir une autre méthode implémentée dans l’exemple ListActivityOnListItemClick suivant :

Capture d’écran d’un SimpleListItem

protected override void OnListItemClick(ListView l, View v, int position, long id)
{
   var t = items[position];
   Android.Widget.Toast.MakeText(this, t, Android.Widget.ToastLength.Short).Show();
}

À présent, l’utilisateur peut toucher une ligne et une Toast alerte s’affiche :

Capture d’écran de Toast qui s’affiche lorsqu’une ligne est tactile

Implémentation d’un ListAdapter

ArrayAdapter<string> est génial en raison de sa simplicité, mais il est extrêmement limité. Toutefois, souvent, vous disposez d’une collection d’entités métier, plutôt que de chaînes que vous souhaitez lier. Par exemple, si vos données se composent d’une collection de classes Employee, vous souhaiterez peut-être que la liste affiche simplement les noms de chaque employé. Pour personnaliser le comportement d’un ListView pour contrôler les données affichées, vous devez implémenter une sous-classe de substitution des BaseAdapter quatre éléments suivants :

  • Nombre : pour indiquer au contrôle le nombre de lignes dans les données.

  • GetView : pour renvoyer une vue pour chaque ligne, renseignée avec des données. Cette méthode a un paramètre pour passer ListView une ligne existante non utilisée pour une réutilisation.

  • GetItemId : retourne un identificateur de ligne (généralement le numéro de ligne, même s’il peut s’agir d’une valeur longue que vous aimez).

  • cet indexeur [int] : pour renvoyer les données associées à un numéro de ligne particulier.

L’exemple de code dans BasicTableAdapter/HomeScreenAdapter.cs montre comment sous-classe BaseAdapter:

public class HomeScreenAdapter : BaseAdapter<string> {
   string[] items;
   Activity context;
   public HomeScreenAdapter(Activity context, string[] items) : base() {
       this.context = context;
       this.items = items;
   }
   public override long GetItemId(int position)
  {
       return position;
   }
   public override string this[int position] {  
       get { return items[position]; }
   }
   public override int Count {
       get { return items.Length; }
   }
   public override View GetView(int position, View convertView, ViewGroup parent)
   {
       View view = convertView; // re-use an existing view, if one is available
      if (view == null) // otherwise create a new one
           view = context.LayoutInflater.Inflate(Android.Resource.Layout.SimpleListItem1, null);
       view.FindViewById<TextView>(Android.Resource.Id.Text1).Text = items[position];
       return view;
   }
}

Utilisation d’un adaptateur personnalisé

L’utilisation de l’adaptateur personnalisé est similaire à celle intégrée ArrayAdapter, en passant un context et les string[] valeurs à afficher :

ListAdapter = new HomeScreenAdapter(this, items);

Étant donné que cet exemple utilise la même disposition de ligne (SimpleListItem1) l’application résultante ressemblera à l’exemple précédent.

Réutiliser l’affichage de lignes

Dans cet exemple, il n’y a que six éléments. Dans la mesure où l’écran peut s’adapter à huit, aucune nouvelle ligne n’est requise. Toutefois, lors de l’affichage de centaines ou de milliers de lignes, il s’agirait d’un gaspillage de mémoire pour créer des centaines ou des milliers d’objets View lorsque seulement huit s’adaptent à l’écran à la fois. Pour éviter cette situation, lorsqu’une ligne disparaît de l’écran, son affichage est placé dans une file d’attente pour une réutilisation. Lorsque l’utilisateur défile, les ListView appels GetView pour demander de nouvelles vues s’affichent , s’ils sont disponibles, passent une vue inutilisée dans le convertView paramètre. Si cette valeur est null, votre code doit créer une instance d’affichage ; sinon, vous pouvez définir à nouveau les propriétés de cet objet et le réutiliser.

La GetView méthode doit suivre ce modèle pour réutiliser les vues de lignes :

public override View GetView(int position, View convertView, ViewGroup parent)
{
   View view = convertView; // re-use an existing view, if one is supplied
   if (view == null) // otherwise create a new one
       view = context.LayoutInflater.Inflate(Android.Resource.Layout.SimpleListItem1, null);
   // set view properties to reflect data for the given row
   view.FindViewById<TextView>(Android.Resource.Id.Text1).Text = items[position];
   // return the view, populated with data, for display
   return view;
}

Les implémentations d’adaptateur personnalisées doivent toujours réutiliser l’objet convertView avant de créer de nouveaux affichages pour s’assurer qu’ils n’ont pas de mémoire insuffisante lors de l’affichage de listes longues.

Certaines implémentations d’adaptateurs (telles que le CursorAdapter) n’ont pas de GetView méthode, elles nécessitent plutôt deux méthodes NewView différentes et BindView qui appliquent la réutilisation des lignes en séparant les responsabilités de GetView deux méthodes. Il existe un CursorAdapter exemple plus loin dans le document.

Activation du défilement rapide

Le défilement rapide permet à l’utilisateur de faire défiler les listes longues en fournissant un « handle » supplémentaire qui agit comme une barre de défilement pour accéder directement à une partie de la liste. Cette capture d’écran montre la poignée de défilement rapide :

Capture d’écran du défilement rapide avec une poignée de défilement

L’affichage de la poignée de défilement rapide est aussi simple que la définition de la FastScrollEnabled propriété sur true:

ListView.FastScrollEnabled = true;

Ajout d’un index de section

Un index de section fournit des commentaires supplémentaires pour les utilisateurs lorsqu’ils font défiler rapidement une liste longue : il indique la « section » vers laquelle ils ont fait défiler. Pour que l’index de section apparaisse, la sous-classe Adaptateur doit implémenter l’interface ISectionIndexer pour fournir le texte de l’index en fonction des lignes affichées :

Capture d’écran de H apparaissant dans la section ci-dessus qui commence par H

Pour implémenter ISectionIndexer , vous devez ajouter trois méthodes à un adaptateur :

  • GetSections : fournit la liste complète des titres d’index de section qui peuvent être affichés. Cette méthode nécessite un tableau d’objets Java afin que le code doit créer à Java.Lang.Object[] partir d’une collection .NET. Dans notre exemple, il retourne une liste des caractères initiaux de la liste en tant que Java.Lang.String .

  • GetPositionForSection : retourne la première position de ligne pour un index de section donné.

  • GetSectionForPosition : renvoie l’index de section à afficher pour une ligne donnée.

L’exemple SectionIndex/HomeScreenAdapter.cs de fichier implémente ces méthodes et un code supplémentaire dans le constructeur. Le constructeur génère l’index de section en boucle sur chaque ligne et en extrayant le premier caractère du titre (les éléments doivent déjà être triés pour que cela fonctionne).

alphaIndex = new Dictionary<string, int>();
for (int i = 0; i < items.Length; i++) { // loop through items
   var key = items[i][0].ToString();
   if (!alphaIndex.ContainsKey(key))
       alphaIndex.Add(key, i); // add each 'new' letter to the index
}
sections = new string[alphaIndex.Keys.Count];
alphaIndex.Keys.CopyTo(sections, 0); // convert letters list to string[]

// Interface requires a Java.Lang.Object[], so we create one here
sectionsObjects = new Java.Lang.Object[sections.Length];
for (int i = 0; i < sections.Length; i++) {
   sectionsObjects[i] = new Java.Lang.String(sections[i]);
}

Avec les structures de données créées, les ISectionIndexer méthodes sont très simples :

public Java.Lang.Object[] GetSections()
{
   return sectionsObjects;
}
public int GetPositionForSection(int section)
{
   return alphaIndexer[sections[section]];
}
public int GetSectionForPosition(int position)
{   // this method isn't called in this example, but code is provided for completeness
    int prevSection = 0;
    for (int i = 0; i < sections.Length; i++)
    {
        if (GetPositionForSection(i) > position)
        {
            break;
        }
        prevSection = i;
    }
    return prevSection;
}

Les titres de votre index de section n’ont pas besoin de mapper 1 :1 à vos sections réelles. C’est pourquoi la GetPositionForSection méthode existe. GetPositionForSection vous donne l’occasion de mapper les index figurant dans votre liste d’index à toutes les sections de votre affichage de liste. Par exemple, vous pouvez avoir un « z » dans votre index, mais vous ne disposez peut-être pas d’une section de table pour chaque lettre. Par conséquent, au lieu de « z » mappé à 26, il peut être mappé à 25 ou 24, ou tout index de section « z » doit être mappé.