Wypełnianie obiektu ListView platformy Xamarin.Android przy użyciu danych
Aby dodać wiersze do elementu ListView
, należy dodać go do układu i zaimplementować za IListAdapter
pomocą metod, które ListView
wywołania wypełniają się. System Android zawiera wbudowane ListActivity
i ArrayAdapter
klasy, których można używać bez definiowania niestandardowego kodu XML lub kodu układu niestandardowego. Klasa ListActivity
automatycznie tworzy ListView
właściwość i uwidacznia ListAdapter
właściwość w celu dostarczenia widoków wierszy do wyświetlenia za pośrednictwem karty.
Wbudowane karty przyjmują identyfikator zasobu widoku jako parametr, który jest używany dla każdego wiersza. Możesz użyć wbudowanych zasobów, takich jak te, Android.Resource.Layout
aby nie trzeba było pisać własnych.
Używanie ciągu ListActivity i ArrayAdapter<>
W przykładzie BasicTable/HomeScreen.cs pokazano , jak używać tych klas do wyświetlania ListView
obiektu w zaledwie kilku wierszach kodu:
[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);
}
}
Obsługa kliknięć wierszy
Zazwyczaj użytkownik ListView
może również dotknąć wiersza, aby wykonać jakąś akcję (np. odtwarzanie utworu lub wywoływanie kontaktu lub wyświetlanie innego ekranu). Aby reagować na dotykanie użytkownika, musi istnieć jeszcze jedna metoda zaimplementowana w ListActivity
obiekcie — OnListItemClick
w następujący sposób:
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();
}
Teraz użytkownik może dotknąć wiersza i Toast
pojawi się alert:
Implementowanie elementu ListAdapter
ArrayAdapter<string>
jest wielki ze względu na jego prostotę, ale jest bardzo ograniczona. Jednak często masz kolekcję jednostek biznesowych, a nie tylko ciągi, które chcesz powiązać.
Jeśli na przykład dane składają się z kolekcji klas Employee, możesz chcieć wyświetlić tylko nazwy każdego pracownika. Aby dostosować zachowanie obiektu , ListView
aby kontrolować, jakie dane są wyświetlane, należy zaimplementować podklasę BaseAdapter
zastępowania następujących czterech elementów:
Count — określa, ile wierszy znajdują się w danych.
GetView — aby zwrócić widok dla każdego wiersza, wypełniony danymi. Ta metoda ma parametr umożliwiający
ListView
przekazanie istniejącego, nieużywanego wiersza do ponownego użycia.GetItemId — zwraca identyfikator wiersza (zazwyczaj numer wiersza, chociaż może to być dowolna długa wartość, którą chcesz).
this[int] indexer — aby zwrócić dane skojarzone z określoną liczbą wierszy.
Przykładowy kod w klasie BasicTableAdapter/HomeScreenAdapter.cs pokazuje, jak podklasy 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;
}
}
Używanie karty niestandardowej
Użycie karty niestandardowej jest podobne do wbudowanej ArrayAdapter
, przekazując context
wartości i string[]
do wyświetlenia:
ListAdapter = new HomeScreenAdapter(this, items);
Ponieważ w tym przykładzie użyto tego samego układu wiersza (SimpleListItem1
), wynikowa aplikacja będzie wyglądać identycznie jak w poprzednim przykładzie.
Ponowne użycie widoku wiersza
W tym przykładzie istnieje tylko sześć elementów. Ponieważ ekran może mieścić się w ośmiu, nie jest wymagane ponowne użycie wiersza. Podczas wyświetlania setek lub tysięcy wierszy byłoby to jednak strata pamięci do utworzenia setek lub tysięcy View
obiektów, gdy na ekranie mieści się tylko osiem. Aby uniknąć tej sytuacji, gdy wiersz zniknie z ekranu, jego widok zostanie umieszczony w kolejce do ponownego użycia. Gdy użytkownik przewija, ListView
wywołania GetView
żądania wyświetlenia nowych widoków — jeśli są dostępne, przekazuje nieużywany widok w parametrze convertView
. Jeśli ta wartość ma wartość null, kod powinien utworzyć nowe wystąpienie widoku, w przeciwnym razie można ponownie ustawić właściwości tego obiektu i ponownie go użyć.
Ta metoda powinna być zgodna GetView
z tym wzorcem, aby ponownie używać widoków wierszy:
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;
}
Implementacje kart niestandardowych powinny zawsze ponownie używać convertView
obiektu przed utworzeniem nowych widoków, aby upewnić się, że nie zabraknie pamięci podczas wyświetlania długich list.
Niektóre implementacje adaptera (takie jak CursorAdapter
) nie mają GetView
metody, a nie wymagają dwóch różnych metod NewView
i BindView
które wymuszają ponowne użycie wierszy, oddzielając obowiązki GetView
dwóch metod. W dalszej części dokumentu znajduje CursorAdapter
się przykład.
Włączanie szybkiego przewijania
Szybkie przewijanie pomaga użytkownikowi przewijać długie listy, zapewniając dodatkowy "uchwyt", który działa jako pasek przewijania, aby bezpośrednio uzyskać dostęp do części listy. Ten zrzut ekranu przedstawia szybki uchwyt przewijania:
Powoduje, że szybkie przewijanie uchwytu jest tak proste, jak ustawienie FastScrollEnabled
właściwości na true
:
ListView.FastScrollEnabled = true;
Dodawanie indeksu sekcji
Indeks sekcji zawiera dodatkową opinię dla użytkowników, gdy szybko przewijają długą listę — pokazuje, do której sekcji się przewinęli. Aby spowodować wyświetlenie indeksu sekcji, podklasa Adapter musi zaimplementować ISectionIndexer
interfejs, aby podać tekst indeksu w zależności od wyświetlanych wierszy:
Aby zaimplementować ISectionIndexer
, należy dodać trzy metody do karty:
GetSections — zawiera pełną listę tytułów indeksu sekcji, które mogą być wyświetlane. Ta metoda wymaga tablicy obiektów Java, więc kod musi utworzyć element
Java.Lang.Object[]
na podstawie kolekcji platformy .NET. W naszym przykładzie zwraca listę początkowych znaków na liście jakoJava.Lang.String
.GetPositionForSection — zwraca pozycję pierwszego wiersza dla danego indeksu sekcji.
GetSectionForPosition — zwraca indeks sekcji, który ma być wyświetlany dla danego wiersza.
Przykładowy SectionIndex/HomeScreenAdapter.cs
plik implementuje te metody i dodatkowy kod w konstruktorze. Konstruktor tworzy indeks sekcji, tworząc pętlę w każdym wierszu i wyodrębniając pierwszy znak tytułu (elementy muszą być już posortowane, aby to działało).
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]);
}
Po utworzeniu ISectionIndexer
struktur danych metody są bardzo proste:
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;
}
Tytuły indeksu sekcji nie muszą być mapowane na rzeczywiste sekcje 1:1. GetPositionForSection
Dlatego metoda istnieje.
GetPositionForSection
Daje możliwość mapowania indeksów na listę indeksów do dowolnych sekcji w widoku listy. Na przykład w indeksie może istnieć "z", ale może nie mieć sekcji tabeli dla każdej litery, więc zamiast "z" mapowania na 26, może być mapowanie na 25 lub 24, lub niezależnie od indeksu sekcji "z" powinno być mapowanie na.