Расширение примера RecyclerView
Базовое приложение, описанное в примере Basic RecyclerView, на самом деле не делает многое. Оно просто прокручивает и отображает фиксированный список элементов фотографии для упрощения просмотра. В реальных приложениях пользователи ожидают, что пользователи смогут взаимодействовать с приложением, касаясь элементов в дисплее. Кроме того, базовый источник данных может изменяться (или изменяться приложением), а содержимое дисплея должно оставаться согласованным с этими изменениями. В следующих разделах вы узнаете, как обрабатывать события щелчка элемента и обновляться RecyclerView
при изменении базового источника данных.
Обработка событий щелчка элемента
Когда пользователь прикасается к элементу в RecyclerView
элементе, создается событие щелчка элемента, чтобы уведомить приложение о том, какой элемент был касался. Это событие не создается RecyclerView
. Вместо этого представление элемента (которое завернуто в держатель представления) обнаруживает касания и сообщает об этих касаниях как события щелчка.
Чтобы проиллюстрировать обработку событий щелчка элемента, в следующих шагах объясняется, как основное приложение для просмотра фотографий изменено, чтобы сообщить о том, какая фотография была касалась пользователя. Когда событие щелчка элемента происходит в примере приложения, происходит следующая последовательность:
CardView
Фотография обнаруживает событие щелчка элемента и уведомляет адаптер.Адаптер перенаправит событие (с сведениями о положении элемента) обработчику элемента.
Обработчик щелчка по элементу действия реагирует на событие щелчка элемента.
Во-первых, вызывается член ItemClick
обработчика событий, который добавляется в PhotoAlbumAdapter
определение класса:
public event EventHandler<int> ItemClick;
Далее добавляется MainActivity
метод обработчика событий с щелчком элемента.
Этот обработчик кратко отображает всплывающее уведомление, указывающее, какой элемент фотографии был касался:
void OnItemClick (object sender, int position)
{
int photoNum = position + 1;
Toast.MakeText(this, "This is photo number " + photoNum, ToastLength.Short).Show();
}
Затем для регистрации обработчика OnItemClick
PhotoAlbumAdapter
требуется строка кода. Хорошее место для этого сразу после PhotoAlbumAdapter
создания:
mAdapter = new PhotoAlbumAdapter (mPhotoAlbum);
mAdapter.ItemClick += OnItemClick;
В этом базовом примере регистрация обработчика выполняется в методе основного действияOnCreate
, но рабочее приложение может зарегистрировать обработчик и отменить регистрацию в нем. Дополнительные сведения см. в OnPause
OnResume
разделе "Жизненный цикл действий".
PhotoAlbumAdapter
Теперь будет вызываться OnItemClick
при получении события щелчка элемента. Следующим шагом является создание обработчика в адаптере, который вызывает это ItemClick
событие. Следующий метод OnClick
добавляется сразу после метода адаптера ItemCount
:
void OnClick (int position)
{
if (ItemClick != null)
ItemClick (this, position);
}
Этот OnClick
метод является прослушивателем адаптера для событий щелчка элемента из представлений элементов. Прежде чем этот прослушиватель может быть зарегистрирован в представлении элемента (с помощью владельца представления элемента), PhotoViewHolder
конструктор должен быть изменен, чтобы принять этот метод в качестве дополнительного аргумента, и зарегистрировать OnClick
в событии представления Click
элемента.
Ниже приведен измененный PhotoViewHolder
конструктор:
public PhotoViewHolder (View itemView, Action<int> listener)
: base (itemView)
{
Image = itemView.FindViewById<ImageView> (Resource.Id.imageView);
Caption = itemView.FindViewById<TextView> (Resource.Id.textView);
itemView.Click += (sender, e) => listener (base.LayoutPosition);
}
Параметр itemView
содержит ссылку на CardView
то, что пользователь коснулся. Обратите внимание, что базовый класс владельца представления знает расположение макета элемента (CardView
), которое оно представляет (через LayoutPosition
свойство), и эта позиция передается методу адаптера OnClick
при возникновении события щелчка элемента. Метод адаптера изменяется, чтобы передать метод адаптера OnCreateViewHolder
OnClick
конструктору держателя представления:
PhotoViewHolder vh = new PhotoViewHolder (itemView, OnClick);
Теперь, когда вы создаете и запускаете пример приложения для просмотра фотографий, касание фотографии в дисплее приведет к отображению всплывающих сообщений о том, какие фотографии касались:
В этом примере демонстрируется только один подход для реализации обработчиков событий с RecyclerView
помощью . Другой подход, который можно использовать здесь, заключается в том, чтобы поместить события в держатель представления и подписаться на эти события адаптером. Если пример приложения для фотографии предоставил возможность редактирования фотографий, для каждого из них потребуются ImageView
TextView
CardView
отдельные события: касаются TextView
EditView
диалогового окна, позволяющего пользователю изменять подпись, и касаются ImageView
средства касания фотографии, позволяющего пользователю обрезать или повернуть фотографию. В зависимости от потребностей приложения необходимо разработать оптимальный подход для обработки и реагирования на события касания.
Чтобы продемонстрировать, как RecyclerView
можно обновить при изменении набора данных, пример приложения просмотра фотографий можно изменить, чтобы случайно выбрать фотографию в источнике данных и переключить ее на первую фотографию. Во-первых, кнопка "Случайный выбор " добавляется в пример макета приложения Main.axml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<Button
android:id="@+id/randPickButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Random Pick" />
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:scrollbars="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
Далее код добавляется в конце метода основного действия OnCreate
, чтобы найти Random Pick
кнопку в макете и присоединить обработчик к нему:
Button randomPickBtn = FindViewById<Button>(Resource.Id.randPickButton);
randomPickBtn.Click += delegate
{
if (mPhotoAlbum != null)
{
// Randomly swap a photo with the first photo:
int idx = mPhotoAlbum.RandomSwap();
}
};
Этот обработчик вызывает метод фотоальбома RandomSwap
при нажатии кнопки "Случайный выбор ". Метод RandomSwap
случайным образом переключает фотографию на первую фотографию в источнике данных, а затем возвращает индекс случайно переключения фотографии. При компиляции и запуске примера приложения с этим кодом нажатие кнопки "Случайный выбор " не приводит к изменению отображения, так как RecyclerView
не известно об изменении источника данных.
Чтобы сохранить RecyclerView
обновление после изменения источника данных, обработчик щелчка случайного выбора должен быть изменен, чтобы вызвать метод адаптера NotifyItemChanged
для каждого элемента в коллекции, который изменился (в этом случае два элемента изменились: первая фотография и переключённая фотография). Это приводит к обновлению отображения таким образом, чтобы оно соответствовало RecyclerView
новому состоянию источника данных:
Button randomPickBtn = FindViewById<Button>(Resource.Id.randPickButton);
randomPickBtn.Click += delegate
{
if (mPhotoAlbum != null)
{
int idx = mPhotoAlbum.RandomSwap();
// First photo has changed:
mAdapter.NotifyItemChanged(0);
// Swapped photo has changed:
mAdapter.NotifyItemChanged(idx);
}
};
Теперь, когда кнопка "Случайный выбор " коснулась, обновите дисплей, RecyclerView
чтобы показать, что фотография вниз в коллекции была перемещена на первую фотографию в коллекции:
Конечно, можно было бы вызвать вместо того, чтобы сделать два вызоваNotifyItemChanged
, но это приведет RecyclerView
к тому, чтобы обновить всю коллекцию, NotifyDataSetChanged
хотя только два элемента в коллекции изменились. Вызовы NotifyItemChanged
значительно эффективнее, чем вызовы NotifyDataSetChanged
.