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


Пример Basic RecyclerView

Чтобы понять, как RecyclerView работает в обычном приложении, в этом разделе рассматривается простой пример кода, который используется RecyclerView для отображения большой коллекции фотографий:

Два снимка экрана приложения RecyclerView, использующего CardViews для отображения фотографий

RecyclerViewer использует CardView для реализации каждого элемента фотографии в макете RecyclerView . RecyclerViewИз-за преимуществ производительности этот пример приложения может быстро прокручивать большую коллекцию фотографий гладко и без заметных задержек.

Пример источника данных

В этом примере приложения источник данных "фотоальбом" (представленный классом PhotoAlbum ) предоставляет RecyclerView содержимое элемента. PhotoAlbum— это коллекция фотографий с подпись; при создании экземпляра, вы получите готовую коллекцию из 32 фотографий:

PhotoAlbum mPhotoAlbum = new PhotoAlbum ();

Каждый экземпляр фотографии в PhotoAlbum предоставляет свойства, позволяющие считывать идентификатор ресурса изображения и PhotoIDстроку подписьCaption. Коллекция фотографий организована таким образом, чтобы доступ к каждой фотографии можно получить индексатором. Например, следующие строки кода обращаются к идентификатору ресурса изображения и подпись для десятой фотографии в коллекции:

int imageId = mPhotoAlbum[9].ImageId;
string caption = mPhotoAlbum[9].Caption;

PhotoAlbum также предоставляет RandomSwap метод, который можно вызвать, чтобы заменить первую фотографию в коллекции случайным образом выбранной фотографией в другом месте коллекции:

mPhotoAlbum.RandomSwap ();

Поскольку сведения о PhotoAlbum реализации не относятся к пониманию RecyclerView, PhotoAlbum исходный код не представлен здесь.

Макет и инициализация

Файл макета Main.axml состоит из одного RecyclerView из LinearLayoutследующих элементов:

<?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">
    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:scrollbars="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />
</LinearLayout>

Обратите внимание, что необходимо использовать полное имя android.support.v7.widget.RecyclerView , так как RecyclerView упаковано в библиотеку поддержки. Метод OnCreate инициализации MainActivity этого макета, создание экземпляра адаптера и подготовка базового источника данных:

public class MainActivity : Activity
{
    RecyclerView mRecyclerView;
    RecyclerView.LayoutManager mLayoutManager;
    PhotoAlbumAdapter mAdapter;
    PhotoAlbum mPhotoAlbum;

    protected override void OnCreate (Bundle bundle)
    {
        base.OnCreate (bundle);

        // Prepare the data source:
        mPhotoAlbum = new PhotoAlbum ();

        // Instantiate the adapter and pass in its data source:
        mAdapter = new PhotoAlbumAdapter (mPhotoAlbum);

        // Set our view from the "main" layout resource:
        SetContentView (Resource.Layout.Main);

        // Get our RecyclerView layout:
        mRecyclerView = FindViewById<RecyclerView> (Resource.Id.recyclerView);

        // Plug the adapter into the RecyclerView:
        mRecyclerView.SetAdapter (mAdapter);

Этот код выполняет следующие действия:

  1. PhotoAlbum Создает экземпляр источника данных.

  2. Передает источник данных фотоальбома конструктору адаптера PhotoAlbumAdapter (который определен далее в этом руководстве). Обратите внимание, что рекомендуется передать источник данных в качестве параметра конструктору адаптера.

  3. Получает из RecyclerView макета.

  4. Подключает адаптер к RecyclerView экземпляру RecyclerViewSetAdapter , вызвав метод, как показано выше.

Диспетчер макетов

Каждый элемент в списке RecyclerView состоит из CardView элемента, содержащего изображение фотографии и фото подпись (сведения рассматриваются в разделе "Владелец представления" ниже). Предопределенный используется LinearLayoutManager для размещения каждой из них CardView в вертикальном расположении прокрутки:

mLayoutManager = new LinearLayoutManager (this);
mRecyclerView.SetLayoutManager (mLayoutManager);

Этот код находится в методе основного OnCreate действия. Конструктор диспетчеру макетов требует контекста, поэтому он MainActivity передается, как this показано выше.

Вместо использования предопределенного LinearLayoutManagerможно подключить пользовательский диспетчер макетов, который отображает два CardView элемента параллельно, реализуя эффект анимации поворота страницы для обхода коллекции фотографий. Далее в этом руководстве вы увидите пример изменения макета, заменив его в другом диспетчере макетов.

Владелец представления

Класс держателя представления называется PhotoViewHolder. Каждый PhotoViewHolder экземпляр содержит ссылки на ImageView связанный элемент строки, TextView который представлен в CardView схеме здесь:

Схема CardView, содержащая ImageView и TextView

PhotoViewHolder является производным от RecyclerView.ViewHolder и содержит свойства для хранения ссылок на них ImageView и TextView показанных в приведенном выше макете. PhotoViewHolder состоит из двух свойств и одного конструктора:

public class PhotoViewHolder : RecyclerView.ViewHolder
{
    public ImageView Image { get; private set; }
    public TextView Caption { get; private set; }

    public PhotoViewHolder (View itemView) : base (itemView)
    {
        // Locate and cache view references:
        Image = itemView.FindViewById<ImageView> (Resource.Id.imageView);
        Caption = itemView.FindViewById<TextView> (Resource.Id.textView);
    }
}

В этом примере PhotoViewHolder кода конструктор передает ссылку на представление родительского элемента (т. е CardView.), которое PhotoViewHolder выполняет оболочку. Обратите внимание, что представление родительского элемента всегда пересылается базовому конструктору. Конструктор PhotoViewHolder вызывает представление родительского элемента, чтобы найти каждую из ссылок на дочернее представление и TextViewImageView сохранить результаты соответственно ImageCaption.FindViewById Позже адаптер получает ссылки на представления из этих свойств, когда он обновляет CardViewдочерние представления с новыми данными.

Дополнительные сведения смRecyclerView.ViewHolder. в справочнике по классу RecyclerView.ViewHolder.

Адаптер

Адаптер загружает каждую RecyclerView строку с данными для конкретной фотографии. Например, для данной фотографии в позиции строки P адаптер находит связанные данные в расположении P в источнике данных и копирует эти данные в элемент строки по позиции P в RecyclerView коллекции. Адаптер использует держатель представления для поиска ссылок на ImageView эту позицию и TextView по этой позиции, чтобы не нужно многократно вызывать FindViewById эти представления, так как пользователь прокручивает коллекцию фотографий и повторно использует представления.

В RecyclerViewer класс адаптера является производным от RecyclerView.Adapter создания PhotoAlbumAdapter:

public class PhotoAlbumAdapter : RecyclerView.Adapter
{
    public PhotoAlbum mPhotoAlbum;

    public PhotoAlbumAdapter (PhotoAlbum photoAlbum)
    {
        mPhotoAlbum = photoAlbum;
    }
    ...
}

Элемент mPhotoAlbum содержит источник данных (фотоальбом), который передается в конструктор. Конструктор копирует фотоальбом в эту переменную-член. Реализованы следующие необходимые RecyclerView.Adapter методы:

  • OnCreateViewHolder — создает экземпляр файла макета элемента и держателя представлений.

  • OnBindViewHolder — загружает данные по указанной позиции в представления, ссылки которых хранятся в заданном держателе представления.

  • ItemCount — возвращает количество элементов в источнике данных.

Диспетчер макетов вызывает эти методы во время размещения элементов внутри RecyclerView. Реализация этих методов рассматривается в следующих разделах.

OnCreateViewHolder

Диспетчер макетов вызывает OnCreateViewHolder , когда RecyclerView требуется новый держатель представления для представления элемента. OnCreateViewHolder Увеличивает представление элемента из файла макета представления и упаковывает представление в новый PhotoViewHolder экземпляр. Конструктор PhotoViewHolder находит и сохраняет ссылки на дочерние представления в макете, как описано ранее в представлении "Владелец представления".

Каждый элемент строки представлен элементом, CardView содержащим ImageView (для фотографии) и (TextViewдля подпись). Этот макет находится в файле PhotoCardView.axml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:card_view="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">
    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        card_view:cardElevation="4dp"
        card_view:cardUseCompatPadding="true"
        card_view:cardCornerRadius="5dp">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:padding="8dp">
            <ImageView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/imageView"
                android:scaleType="centerCrop" />
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceMedium"
                android:textColor="#333333"
                android:text="Caption"
                android:id="@+id/textView"
                android:layout_gravity="center_horizontal"
                android:layout_marginLeft="4dp" />
        </LinearLayout>
    </android.support.v7.widget.CardView>
</FrameLayout>

Этот макет представляет один элемент строки в элементе RecyclerView. Метод OnBindViewHolder (описанный ниже) копирует данные из источника данных в ImageView макет и TextView этот макет. OnCreateViewHolder Раздувает этот макет для заданного расположения фотографии в RecyclerView новом PhotoViewHolder экземпляре (который находит и кэширует ссылки на ImageView представления и TextView дочерние представления в связанном CardView макете):

public override RecyclerView.ViewHolder
    OnCreateViewHolder (ViewGroup parent, int viewType)
{
    // Inflate the CardView for the photo:
    View itemView = LayoutInflater.From (parent.Context).
                Inflate (Resource.Layout.PhotoCardView, parent, false);

    // Create a ViewHolder to hold view references inside the CardView:
    PhotoViewHolder vh = new PhotoViewHolder (itemView);
    return vh;
}

Полученный экземпляр vhвладельца представления возвращается вызывающей стороне (диспетчер макета).

OnBindViewHolder

Когда диспетчер макетов готов отобразить определенное представление в RecyclerViewвидимой области экрана, он вызывает метод адаптера OnBindViewHolder для заполнения элемента в указанной позиции строки с содержимым из источника данных. OnBindViewHolderполучает сведения о фотографии для указанной позиции строки (ресурс изображения фотографии и строку для подпись фотографии) и копирует эти данные в связанные представления. Представления находятся через ссылки, хранящиеся в объекте владельца представления (который передается через holder параметр):

public override void
    OnBindViewHolder (RecyclerView.ViewHolder holder, int position)
{
    PhotoViewHolder vh = holder as PhotoViewHolder;

    // Load the photo image resource from the photo album:
    vh.Image.SetImageResource (mPhotoAlbum[position].PhotoID);

    // Load the photo caption from the photo album:
    vh.Caption.Text = mPhotoAlbum[position].Caption;
}

Перед использованием объекта, передаваемого в представление, необходимо сначала привести в производный тип держателя представления (в данном случае PhotoViewHolder). Адаптер загружает ресурс изображения в представление, на которое ссылается свойство владельца Image представления, и копирует подпись текст в представление, на которое ссылается свойство владельца Caption представления. Это привязывает связанное представление с данными.

Обратите внимание, что OnBindViewHolder это код, который занимается непосредственно структурой данных. В этом случае вы узнаете, OnBindViewHolder как сопоставить RecyclerView положение элемента с соответствующим элементом данных в источнике данных. Сопоставление является простым в этом случае, так как позиция может использоваться в качестве индекса массива в фотоальбоме; однако для создания такого сопоставления может потребоваться более сложный источник данных.

ItemCount

Метод ItemCount возвращает количество элементов в коллекции данных. В примере приложения просмотра фотографий количество элементов — это количество фотографий в фотоальбоме:

public override int ItemCount
{
    get { return mPhotoAlbum.NumPhotos; }
}

Дополнительные сведения смRecyclerView.Adapter. в справочнике по классу RecyclerView.Adapter.

Объединение всего вместе

Результирующая RecyclerView реализация примера фото-приложения состоит из MainActivity кода, который создает источник данных, диспетчер макетов и адаптер. MainActivitymRecyclerView создает экземпляр, создает экземпляр источника данных и адаптера, а также подключается к диспетчеру макета и адаптеру:

public class MainActivity : Activity
{
    RecyclerView mRecyclerView;
    RecyclerView.LayoutManager mLayoutManager;
    PhotoAlbumAdapter mAdapter;
    PhotoAlbum mPhotoAlbum;

    protected override void OnCreate (Bundle bundle)
    {
        base.OnCreate (bundle);
        mPhotoAlbum = new PhotoAlbum();
        SetContentView (Resource.Layout.Main);
        mRecyclerView = FindViewById<RecyclerView> (Resource.Id.recyclerView);

        // Plug in the linear layout manager:
        mLayoutManager = new LinearLayoutManager (this);
        mRecyclerView.SetLayoutManager (mLayoutManager);

        // Plug in my adapter:
        mAdapter = new PhotoAlbumAdapter (mPhotoAlbum);
        mRecyclerView.SetAdapter (mAdapter);
    }
}

PhotoViewHolder находит и кэширует ссылки на представление:

public class PhotoViewHolder : RecyclerView.ViewHolder
{
    public ImageView Image { get; private set; }
    public TextView Caption { get; private set; }

    public PhotoViewHolder (View itemView) : base (itemView)
    {
        // Locate and cache view references:
        Image = itemView.FindViewById<ImageView> (Resource.Id.imageView);
        Caption = itemView.FindViewById<TextView> (Resource.Id.textView);
    }
}

PhotoAlbumAdapter реализует три обязательных переопределения метода:

public class PhotoAlbumAdapter : RecyclerView.Adapter
{
    public PhotoAlbum mPhotoAlbum;
    public PhotoAlbumAdapter (PhotoAlbum photoAlbum)
    {
        mPhotoAlbum = photoAlbum;
    }

    public override RecyclerView.ViewHolder
        OnCreateViewHolder (ViewGroup parent, int viewType)
    {
        View itemView = LayoutInflater.From (parent.Context).
                    Inflate (Resource.Layout.PhotoCardView, parent, false);
        PhotoViewHolder vh = new PhotoViewHolder (itemView);
        return vh;
    }

    public override void
        OnBindViewHolder (RecyclerView.ViewHolder holder, int position)
    {
        PhotoViewHolder vh = holder as PhotoViewHolder;
        vh.Image.SetImageResource (mPhotoAlbum[position].PhotoID);
        vh.Caption.Text = mPhotoAlbum[position].Caption;
    }

    public override int ItemCount
    {
        get { return mPhotoAlbum.NumPhotos; }
    }
}

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

Два снимка экрана: приложение просмотра фотографий с вертикальной прокруткой карта

Если тени не рисуются (как показано на снимке экрана выше), измените свойства/AndroidManifest.xml и добавьте в элемент следующий параметр атрибута <application> :

android:hardwareAccelerated="true"

Это базовое приложение поддерживает только просмотр фотоальбома. Он не отвечает на события касания элементов и не обрабатывает изменения в базовых данных. Эта функция добавлена в расширение примера RecyclerView.

Изменение макетаManager

RecyclerViewИз-за гибкости приложение легко изменить для использования другого диспетчера макетов. В следующем примере он изменяется, чтобы отобразить фотоальбом с макетом сетки, который прокручивается по горизонтали, а не с вертикальным линейным макетом. Для этого создается экземпляр диспетчера макетов, который будет использоваться GridLayoutManager следующим образом:

mLayoutManager = new GridLayoutManager(this, 2, GridLayoutManager.Horizontal, false);

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

Пример снимка экрана приложения с горизонтальной прокруткой фотографий в сетке

Изменив только одну строку кода, можно изменить приложение для просмотра фотографий, чтобы использовать другой макет с другим поведением. Обратите внимание, что ни код адаптера, ни XML макета не должны быть изменены для изменения стиля макета.

В следующем разделе расширение примера RecyclerView это базовое пример приложения расширено для обработки событий щелчка элемента и обновления RecyclerView при изменении базового источника данных.