Share via


Auffüllen einer Xamarin.Android ListView mit Daten

Zum Hinzufügen von Zeilen zu einem ListView Layout müssen Sie sie ihrem Layout hinzufügen und eine IListAdapter mit Methoden implementieren, mit denen die ListView Aufrufe selbst aufgefüllt werden. Android enthält integrierte ListActivity Und ArrayAdapter Klassen, die Sie verwenden können, ohne benutzerdefinierte Layout-XML oder Code zu definieren. Die ListActivity Klasse erstellt automatisch eine ListView Eigenschaft und macht sie ListAdapter verfügbar, um die Zeilenansichten anzugeben, die über einen Adapter angezeigt werden.

Die integrierten Adapter verwenden eine Ansichtsressourcen-ID als Parameter, der für jede Zeile verwendet wird. Sie können integrierte Ressourcen verwenden, z. B. solche Android.Resource.Layout , in denen Sie keine eigenen schreiben müssen.

Verwenden der ListActivity- und ArrayAdapter-Zeichenfolge<>

Das Beispiel "BasicTable/HomeScreen.cs " veranschaulicht die Verwendung dieser Klassen zum Anzeigen einer ListView Klasse in nur wenigen Codezeilen:

[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);
   }
}

Behandeln von Zeilenklicks

ListView In der Regel ermöglicht es dem Benutzer auch, eine Zeile zu berühren, um eine Aktion auszuführen (z. B. das Wiedergeben eines Lieds oder das Aufrufen eines Kontakts oder das Anzeigen eines anderen Bildschirms). Um auf Benutzereingaben zu reagieren, muss eine weitere Methode in der ListActivityOnListItemClick wie folgt – implementiert werden:

Screenshot eines 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();
}

Jetzt kann der Benutzer eine Zeile berühren, und eine Toast Warnung wird angezeigt:

Screenshot des Popups, das angezeigt wird, wenn eine Zeile berührt wird

Implementieren eines ListAdapter

ArrayAdapter<string> ist großartig wegen seiner Einfachheit, aber es ist extrem begrenzt. Häufig verfügen Sie jedoch über eine Sammlung von Geschäftsentitäten und nicht nur über Zeichenfolgen, die Sie binden möchten. Wenn Ihre Daten beispielsweise aus einer Sammlung von Mitarbeiterklassen bestehen, möchten Sie vielleicht, dass die Liste nur die Namen der einzelnen Mitarbeiter anzeigt. Um das Verhalten eines Steuerelements ListView anzupassen, um zu steuern, welche Daten angezeigt werden, müssen Sie eine Unterklasse zum BaseAdapter Überschreiben der folgenden vier Elemente implementieren:

  • Count – So teilen Sie dem Steuerelement mit, wie viele Zeilen in den Daten enthalten sind.

  • GetView – Um eine Ansicht für jede Zeile zurückzugeben, aufgefüllt mit Daten. Diese Methode weist einen Parameter auf, mit dem eine ListView vorhandene, nicht verwendete Zeile für die erneute Verwendung übergeben werden soll.

  • GetItemId – Zurückgeben eines Zeilenbezeichners (normalerweise die Zeilennummer, obwohl es sich um einen beliebigen langen Wert handeln kann).

  • this[int] indexer – So geben Sie die Mit einer bestimmten Zeilennummer verknüpften Daten zurück.

Der Beispielcode in BasicTableAdapter/HomeScreenAdapter.cs veranschaulicht, wie Unterklassen 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;
   }
}

Verwenden eines benutzerdefinierten Adapters

Die Verwendung des benutzerdefinierten Adapters ist mit dem integrierten ArrayAdapterAdapter vergleichbar, wobei die context Werte übergeben werden, die string[] angezeigt werden sollen:

ListAdapter = new HomeScreenAdapter(this, items);

Da in diesem Beispiel dasselbe Zeilenlayout (SimpleListItem1) verwendet wird, sieht die resultierende Anwendung mit dem vorherigen Beispiel identisch aus.

Erneute Verwendung der Zeilenansicht

In diesem Beispiel gibt es nur sechs Elemente. Da der Bildschirm acht passen kann, ist keine erneute Verwendung der Zeile erforderlich. Bei der Anzeige von Hunderten oder Tausenden von Zeilen wäre es jedoch eine Speicherverschwendung, um Hunderte oder Tausende von View Objekten zu erstellen, wenn nur acht gleichzeitig auf den Bildschirm passen. Um diese Situation zu vermeiden, wird die Anzeige einer Zeile aus dem Bildschirm zur erneuten Verwendung in einer Warteschlange platziert. Während der Benutzer scrollt, werden die ListView Aufrufe GetView zum Anfordern neuer Ansichten zur Anzeige aufgerufen – sofern verfügbar, übergibt sie eine nicht verwendete Ansicht im convertView Parameter. Wenn dieser Wert null ist, sollte ihr Code eine neue Ansichtsinstanz erstellen, andernfalls können Sie die Eigenschaften dieses Objekts erneut festlegen und erneut verwenden.

Die GetView Methode sollte diesem Muster folgen, um Zeilenansichten erneut zu verwenden:

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;
}

Benutzerdefinierte Adapterimplementierungen sollten das convertView Objekt immer erneut verwenden, bevor neue Ansichten erstellt werden, um sicherzustellen, dass beim Anzeigen langer Listen kein Arbeitsspeicher mehr vorhanden ist.

Einige Adapterimplementierungen (z. B. die CursorAdapter) verfügen nicht über eine GetView Methode, sondern erfordern zwei verschiedene Methoden NewView und BindView die die erneute Verwendung der Zeile erzwingen, indem die Verantwortlichkeiten in GetView zwei Methoden getrennt werden. Es gibt ein CursorAdapter Beispiel weiter unten im Dokument.

Aktivieren des schnellen Bildlaufs

Schnelles Scrollen hilft dem Benutzer, durch lange Listen zu scrollen, indem ein zusätzlicher "Handle" bereitgestellt wird, der als Bildlaufleiste fungiert, um direkt auf einen Teil der Liste zuzugreifen. Dieser Screenshot zeigt den schnellen Bildlaufpunkt:

Screenshot des schnellen Bildlaufs mit einem Bildlaufpunkt

Die Anzeige des schnellen Bildlaufpunkts ist so einfach wie das Festlegen der FastScrollEnabled Eigenschaft auf true:

ListView.FastScrollEnabled = true;

Hinzufügen eines Abschnittsindex

Ein Abschnittsindex bietet zusätzliches Feedback für Benutzer, wenn sie schnell durch eine lange Liste scrollen – es zeigt an, zu welchem "Abschnitt" sie scrollen. Damit der Abschnittsindex angezeigt wird, muss die Adapterunterklasse die ISectionIndexer Schnittstelle implementieren, um den Indextext abhängig von den angezeigten Zeilen anzugeben:

Screenshot von H, der oben angezeigt wird, der mit H beginnt

Zum Implementieren ISectionIndexer müssen Sie einem Adapter drei Methoden hinzufügen:

  • GetSections – Stellt die vollständige Liste der Abschnittsindextitel bereit, die angezeigt werden können. Diese Methode erfordert ein Array von Java Objects, sodass der Code eine Java.Lang.Object[] aus einer .NET-Auflistung erstellen muss. In unserem Beispiel wird eine Liste der Anfangszeichen in der Liste als Java.Lang.String .

  • GetPositionForSection – Gibt die erste Zeilenposition für einen bestimmten Abschnittsindex zurück.

  • GetSectionForPosition – Gibt den Abschnittsindex zurück, der für eine bestimmte Zeile angezeigt werden soll.

Die Beispieldatei SectionIndex/HomeScreenAdapter.cs implementiert diese Methoden und zusätzlichen Code im Konstruktor. Der Konstruktor erstellt den Abschnittsindex, indem er jede Zeile durchläuft und das erste Zeichen des Titels extrahiert (die Elemente müssen bereits sortiert werden, damit dies funktioniert).

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]);
}

Mit den erstellten Datenstrukturen sind die ISectionIndexer Methoden sehr einfach:

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;
}

Ihre Abschnittsindextitel müssen 1:1 nicht ihren tatsächlichen Abschnitten zuordnen. Aus diesem Grund ist die GetPositionForSection Methode vorhanden. GetPositionForSection bietet Ihnen die Möglichkeit, alle Indizes in Ihrer Indexliste allen Abschnitten in Ihrer Listenansicht zuzuordnen. Sie können z. B. ein "z" in Ihrem Index haben, aber möglicherweise keinen Tabellenabschnitt für jeden Buchstaben haben. Anstelle der Zuordnung von "z" zu 26 kann die Zuordnung zu 25 oder 24 erfolgen, oder der Abschnittsindex "z" sollte zugeordnet werden.