Заполнение Xamarin.Android ListView данными
Чтобы добавить строки в ListView
макет, необходимо добавить его в макет и реализовать IListAdapter
методы, которые ListView
вызываются для заполнения. Android включает встроенные ListActivity
и ArrayAdapter
классы, которые можно использовать без определения xml-кода пользовательского макета или кода. Класс ListActivity
автоматически создает ListView
и предоставляет ListAdapter
свойство для предоставления представлений строк для отображения через адаптер.
Встроенные адаптеры принимают идентификатор ресурса представления в качестве параметра, который используется для каждой строки. Вы можете использовать встроенные ресурсы, такие как те, в Android.Resource.Layout
которых нет необходимости писать собственные ресурсы.
Использование строки ListActivity и ArrayAdapter<>
В примере BasicTable/HomeScreen.cs показано, как использовать эти классы для отображения ListView
только в нескольких строках кода:
[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);
}
}
Обработка щелчков строк
ListView
Обычно пользователь также позволяет пользователю касаться строки для выполнения некоторых действий (таких как воспроизведение песни, вызов контакта или отображение другого экрана). Чтобы реагировать на касания пользователей, необходимо еще один метод, реализованный в ListActivity
OnListItemClick
следующем:
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();
}
Теперь пользователь может коснуться строки и появится оповещение Toast
:
Реализация ListAdapter
ArrayAdapter<string>
отлично из-за его простоты, но это чрезвычайно ограничено. Однако часто у вас есть коллекция бизнес-сущностей, а не только строк, которые требуется привязать.
Например, если данные состоят из коллекции классов Employee, может потребоваться, чтобы список отображал только имена каждого сотрудника. Чтобы настроить поведение ListView
элемента управления отображаемыми данными, необходимо реализовать подкласс BaseAdapter
переопределения следующих четырех элементов:
Количество . Чтобы сообщить элементу управления, сколько строк находятся в данных.
GetView — чтобы вернуть представление для каждой строки, заполненной данными. Этот метод имеет параметр для
ListView
передачи существующей неиспользуемой строки для повторного использования.GetItemId — возвращает идентификатор строки (обычно номер строки, хотя это может быть любое длинное значение, которое вы хотите).
индексатор [int] — чтобы вернуть данные, связанные с определенным номером строки.
Пример кода в BasicTableAdapter/HomeScreenAdapter.cs демонстрирует, как подкласс 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;
}
}
Использование пользовательского адаптера
Использование пользовательского адаптера аналогично встроенному ArrayAdapter
, передавая значения context
и string[]
отображаемые значения:
ListAdapter = new HomeScreenAdapter(this, items);
Так как в этом примере используется тот же макет строки (SimpleListItem1
) результирующее приложение будет выглядеть идентично предыдущему примеру.
Повторное использование представления строк
В этом примере есть только шесть элементов. Так как экран может соответствовать восьми, не требуется повторного использования строк. При отображении сотен или тысяч строк, однако, это была бы трата памяти, чтобы создать сотни или тысячи View
объектов, когда только восемь помещаются на экране одновременно. Чтобы избежать этой ситуации, когда строка исчезает с экрана, его представление помещается в очередь для повторного использования. По мере прокрутки пользователя вызовы GetView
для запроса новых представлений для отображения — если он доступен, ListView
он передает неиспользуемое представление в параметреconvertView
. Если это значение равно NULL, код должен создать новый экземпляр представления, в противном случае можно повторно задать свойства этого объекта и повторно использовать его.
Метод GetView
должен соответствовать этому шаблону для повторного использования представлений строк:
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;
}
Реализации пользовательских адаптеров всегда следует повторно использовать convertView
объект перед созданием новых представлений, чтобы убедиться, что при отображении длинных списков не хватает памяти.
Некоторые реализации адаптера (напримерCursorAdapter
, метод) не имеют GetView
метода, а требуют двух разных методов и BindView
принудительного повторного использования строк путем разделения обязанностей GetView
двух методовNewView
. Далее в документе есть CursorAdapter
пример.
Включение быстрой прокрутки
Быстрая прокрутка помогает пользователю прокручивать длинные списки, предоставляя дополнительный "дескриптор", который выступает в качестве полосы прокрутки для прямого доступа к части списка. На снимком снимка экрана показана быстрая обработка прокрутки:
Чтобы быстро прокручивающийся дескриптор отображалось так же просто, как задать FastScrollEnabled
для свойства true
значение :
ListView.FastScrollEnabled = true;
Добавление индекса раздела
Индекс раздела предоставляет дополнительные отзывы для пользователей при быстрой прокрутке по длинному списку— он показывает, на какой раздел они прокрутили. Чтобы индекс раздела отображался подкласс Адаптера, необходимо реализовать ISectionIndexer
интерфейс для предоставления текста индекса в зависимости от отображаемых строк:
Чтобы реализовать ISectionIndexer
, необходимо добавить три метода в адаптер:
GetSections — предоставляет полный список заголовков индексов разделов, которые можно отобразить. Для этого метода требуется массив объектов Java, поэтому коду необходимо создать из
Java.Lang.Object[]
коллекции .NET. В нашем примере возвращается список начальных символов в списке какJava.Lang.String
.GetPositionForSection — возвращает первую позицию строки для заданного индекса раздела.
GetSectionForPosition — возвращает индекс раздела, отображаемый для заданной строки.
Пример SectionIndex/HomeScreenAdapter.cs
файла реализует эти методы и дополнительный код в конструкторе. Конструктор создает индекс раздела путем цикла по каждой строке и извлечения первого символа заголовка (элементы уже должны быть отсортированы для работы).
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]);
}
При создании ISectionIndexer
структур данных методы очень просты:
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;
}
Названия индексов разделов не должны сопоставляться с фактическими разделами. Именно поэтому GetPositionForSection
метод существует.
GetPositionForSection
позволяет сопоставить все индексы в списке индексов с любыми разделами в представлении списка. Например, у вас может быть "z" в индексе, но у вас может не быть раздела таблицы для каждой буквы, поэтому вместо "z" сопоставление с 26 может быть сопоставлено с 25 или 24, или любой индекс раздела "z" должен сопоставляться с.