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 ListActivity
OnListItemClick
suivant :
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 :
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 :
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 :
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 queJava.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é.