Поделиться через


Расширение примера RecyclerView

Базовое приложение, описанное в примере Basic RecyclerView, на самом деле не делает многое. Оно просто прокручивает и отображает фиксированный список элементов фотографии для упрощения просмотра. В реальных приложениях пользователи ожидают, что пользователи смогут взаимодействовать с приложением, касаясь элементов в дисплее. Кроме того, базовый источник данных может изменяться (или изменяться приложением), а содержимое дисплея должно оставаться согласованным с этими изменениями. В следующих разделах вы узнаете, как обрабатывать события щелчка элемента и обновляться RecyclerView при изменении базового источника данных.

Обработка событий щелчка элемента

Когда пользователь прикасается к элементу в RecyclerViewэлементе, создается событие щелчка элемента, чтобы уведомить приложение о том, какой элемент был касался. Это событие не создается RecyclerView . Вместо этого представление элемента (которое завернуто в держатель представления) обнаруживает касания и сообщает об этих касаниях как события щелчка.

Чтобы проиллюстрировать обработку событий щелчка элемента, в следующих шагах объясняется, как основное приложение для просмотра фотографий изменено, чтобы сообщить о том, какая фотография была касалась пользователя. Когда событие щелчка элемента происходит в примере приложения, происходит следующая последовательность:

  1. CardView Фотография обнаруживает событие щелчка элемента и уведомляет адаптер.

  2. Адаптер перенаправит событие (с сведениями о положении элемента) обработчику элемента.

  3. Обработчик щелчка по элементу действия реагирует на событие щелчка элемента.

Во-первых, вызывается член 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();
}

Затем для регистрации обработчика OnItemClickPhotoAlbumAdapterтребуется строка кода. Хорошее место для этого сразу после PhotoAlbumAdapter создания:

mAdapter = new PhotoAlbumAdapter (mPhotoAlbum);
mAdapter.ItemClick += OnItemClick;

В этом базовом примере регистрация обработчика выполняется в методе основного действияOnCreate, но рабочее приложение может зарегистрировать обработчик и отменить регистрацию в нем. Дополнительные сведения см. в OnPauseOnResume разделе "Жизненный цикл действий".

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 при возникновении события щелчка элемента. Метод адаптера изменяется, чтобы передать метод адаптера OnCreateViewHolderOnClick конструктору держателя представления:

PhotoViewHolder vh = new PhotoViewHolder (itemView, OnClick);

Теперь, когда вы создаете и запускаете пример приложения для просмотра фотографий, касание фотографии в дисплее приведет к отображению всплывающих сообщений о том, какие фотографии касались:

Пример всплывающего элемента, отображаемого при нажатии карточки фотографии

В этом примере демонстрируется только один подход для реализации обработчиков событий с RecyclerViewпомощью . Другой подход, который можно использовать здесь, заключается в том, чтобы поместить события в держатель представления и подписаться на эти события адаптером. Если пример приложения для фотографии предоставил возможность редактирования фотографий, для каждого из них потребуются ImageViewTextViewCardViewотдельные события: касаются TextViewEditView диалогового окна, позволяющего пользователю изменять подпись, и касаются 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.