Ejemplo básico de RecyclerView

Para comprender cómo RecyclerView funciona en una aplicación típica, en este tema se explora la aplicación de ejemplo RecyclerViewer , un ejemplo de código sencillo que usa RecyclerView para mostrar una gran colección de fotos:

Dos capturas de pantalla de una aplicación RecyclerView que usa CardViews para mostrar fotos

RecyclerViewer usa CardView para implementar cada elemento de fotografía en el RecyclerView diseño. Debido a las ventajas de RecyclerViewrendimiento, esta aplicación de ejemplo es capaz de desplazarse rápidamente por una gran colección de fotos sin problemas y sin retrasos notables.

Un origen de datos de ejemplo

En esta aplicación de ejemplo, un origen de datos de "álbum de fotos" (representado por la PhotoAlbum clase) proporciona RecyclerView contenido de elemento. PhotoAlbum es una colección de fotos con subtítulos; cuando se crea una instancia, se obtiene una colección preparada de 32 fotos:

PhotoAlbum mPhotoAlbum = new PhotoAlbum ();

Cada instancia de foto de PhotoAlbum expone propiedades que le permiten leer su identificador de recurso de imagen, PhotoID, y su cadena de subtítulo, Caption. La colección de fotos se organiza de forma que un indexador pueda acceder a cada foto. Por ejemplo, las siguientes líneas de código acceden al identificador de recurso de imagen y subtítulo para la décima foto de la colección:

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

PhotoAlbum también proporciona un RandomSwap método que se puede llamar para intercambiar la primera foto de la colección con una foto elegida aleatoriamente en otra parte de la colección:

mPhotoAlbum.RandomSwap ();

Dado que los detalles de implementación de PhotoAlbum no son relevantes para comprender RecyclerView, el PhotoAlbum código fuente no se presenta aquí. El código fuente para PhotoAlbum está disponible en PhotoAlbum.cs en la aplicación de ejemplo RecyclerViewer .

Diseño e inicialización

El archivo de diseño, Main.axml, consta de un único RecyclerView dentro de :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>

Tenga en cuenta que debe usar el nombre completo android.support.v7.widget.RecyclerView porque RecyclerView está empaquetado en una biblioteca de soporte técnico. El OnCreate método de MainActivity inicializa este diseño, crea una instancia del adaptador y prepara el origen de datos subyacente:

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);

Este código hace lo siguiente:

  1. Crea una instancia del PhotoAlbum origen de datos.

  2. Pasa el origen de datos del álbum de fotos al constructor del adaptador ( PhotoAlbumAdapter que se define más adelante en esta guía). Tenga en cuenta que se considera un procedimiento recomendado pasar el origen de datos como parámetro al constructor del adaptador.

  3. Obtiene del RecyclerView diseño.

  4. Conecta el adaptador a la RecyclerView instancia llamando al RecyclerViewSetAdapter método como se muestra anteriormente.

Administrador de diseño

Cada elemento RecyclerView de consta de un CardView objeto que contiene una imagen de foto y una subtítulo de fotos (los detalles se tratan en la sección Titular de la vista a continuación). El predefinido LinearLayoutManager se usa para diseñar cada CardView uno en una disposición de desplazamiento vertical:

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

Este código reside en el método de la OnCreate actividad principal. El constructor para el administrador de diseño requiere un contexto, por lo que MainActivity se pasa usando this como se ha visto anteriormente.

En lugar de usar el predefinido LinearLayoutManager, puede conectar un administrador de diseño personalizado que muestre dos CardView elementos en paralelo, implementando un efecto de animación de giro de página para recorrer la colección de fotos. Más adelante en esta guía, verá un ejemplo de cómo modificar el diseño intercambiando en un administrador de diseño diferente.

Titular de la vista

La clase del titular de la vista se denomina PhotoViewHolder. Cada PhotoViewHolder instancia contiene referencias a ImageView y TextView a un elemento de fila asociado, que se proporciona en un CardView como diagrama aquí:

Diagrama de CardView que contiene imageView y TextView

PhotoViewHolder deriva de RecyclerView.ViewHolder y contiene propiedades para almacenar referencias a ImageView y TextView que se muestran en el diseño anterior. PhotoViewHolder consta de dos propiedades y un constructor:

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);
    }
}

En este ejemplo de código, el PhotoViewHolder constructor se pasa una referencia a la vista de elementos primarios () CardViewque PhotoViewHolder se ajusta. Tenga en cuenta que siempre reenvía la vista de elemento primario al constructor base. El PhotoViewHolder constructor llama FindViewById a en la vista de elementos primarios para buscar cada una de sus referencias de vista secundarias y TextViewImageView , almacenando los resultados en las Image propiedades yCaption, respectivamente. Posteriormente, el adaptador recupera las referencias de vista de estas propiedades cuando actualiza estas CardViewvistas secundarias con nuevos datos.

Para obtener más información sobre RecyclerView.ViewHolder, vea la referencia de la clase RecyclerView.ViewHolder.

Adapter (Adaptador)

El adaptador carga cada RecyclerView fila con datos para una fotografía determinada. Para una fotografía determinada en la posición de fila P, por ejemplo, el adaptador localiza los datos asociados en la posición P dentro del origen de datos y copia estos datos en el elemento de fila en la posición P de la RecyclerView colección. El adaptador usa el soporte de vista para buscar las referencias de y ImageViewTextView en esa posición para que no tenga que llamar FindViewById repetidamente a esas vistas cuando el usuario se desplaza por la colección de fotografías y reutiliza las vistas.

En RecyclerViewer, una clase de adaptador se deriva de RecyclerView.Adapter para crear PhotoAlbumAdapter:

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

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

El mPhotoAlbum miembro contiene el origen de datos (el álbum de fotos) que se pasa al constructor; el constructor copia el álbum de fotos en esta variable miembro. Se implementan los métodos necesarios RecyclerView.Adapter siguientes:

  • OnCreateViewHolder : crea una instancia del archivo de diseño del elemento y del titular de la vista.

  • OnBindViewHolder : carga los datos en la posición especificada en las vistas cuyas referencias se almacenan en el titular de vista especificado.

  • ItemCount : devuelve el número de elementos del origen de datos.

El administrador de diseño llama a estos métodos mientras coloca elementos dentro de RecyclerView. La implementación de estos métodos se examina en las secciones siguientes.

OnCreateViewHolder

El administrador de diseño llama OnCreateViewHolder cuando RecyclerView necesita un nuevo titular de vista para representar un elemento. OnCreateViewHolder infla la vista de elemento desde el archivo de diseño de la vista y ajusta la vista en una nueva PhotoViewHolder instancia. El PhotoViewHolder constructor localiza y almacena referencias a vistas secundarias en el diseño, tal y como se ha descrito anteriormente en View Holder.

Cada elemento de fila se representa mediante un CardView que contiene un ImageView (para la foto) y un TextView (para el subtítulo). Este diseño reside en el archivo 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>

Este diseño representa un único elemento de fila en .RecyclerView El OnBindViewHolder método (descrito a continuación) copia datos del origen de datos en ImageView y TextView de este diseño. OnCreateViewHolderinfla este diseño para una ubicación de foto determinada en RecyclerView y crea una instancia de una nueva PhotoViewHolder instancia (que localiza y almacena en caché las referencias a las vistas secundarias y TextView en ImageView el diseño asociadoCardView):

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;
}

La instancia resultante del titular de la vista, vh, se devuelve al autor de la llamada (el administrador de diseño).

OnBindViewHolder

Cuando el administrador de diseño está listo para mostrar una vista determinada en el RecyclerViewárea de pantalla visible del adaptador, llama al método del OnBindViewHolder adaptador para rellenar el elemento en la posición de fila especificada con contenido del origen de datos. OnBindViewHolderobtiene la información de la foto para la posición de fila especificada (el recurso de imagen de la foto y la cadena del subtítulo de la foto) y copia estos datos en las vistas asociadas. Las vistas se encuentran a través de referencias almacenadas en el objeto del titular de la vista (que se pasa a través del holder parámetro ):

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;
}

El objeto del titular de vista pasado primero debe convertirse en el tipo de titular de vista derivado (en este caso, PhotoViewHolder) antes de usarlo. El adaptador carga el recurso de imagen en la vista a la que hace referencia la propiedad del Image titular de la vista y copia el texto subtítulo en la vista a la que hace referencia la propiedad del titular de Caption la vista. Esto enlaza la vista asociada con sus datos.

Observe que OnBindViewHolder es el código que se ocupa directamente de la estructura de los datos. En este caso, OnBindViewHolder comprende cómo asignar la posición del RecyclerView elemento a su elemento de datos asociado en el origen de datos. La asignación es sencilla en este caso porque la posición se puede usar como índice de matriz en el álbum de fotos; Sin embargo, los orígenes de datos más complejos pueden requerir código adicional para establecer dicha asignación.

ItemCount

El ItemCount método devuelve el número de elementos de la colección de datos. En la aplicación visor de fotos de ejemplo, el recuento de elementos es el número de fotos en el álbum de fotos:

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

Para obtener más información sobre RecyclerView.Adapter, vea la referencia de la clase RecyclerView.Adapter.

Juntarlo todo

La implementación resultante RecyclerView de la aplicación de fotos de ejemplo consta de código que crea el origen de MainActivity datos, el administrador de diseño y el adaptador. MainActivity crea la mRecyclerView instancia, crea instancias del origen de datos y el adaptador, y conecta el administrador de diseño y el adaptador:

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 busca y almacena en caché las referencias de vista:

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 implementa las tres invalidaciones de método necesarias:

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; }
    }
}

Cuando este código se compila y ejecuta, crea la aplicación básica de visualización de fotos, como se muestra en las capturas de pantalla siguientes:

Dos capturas de pantalla de la aplicación de visualización de fotos con tarjetas de fotos de desplazamiento vertical

Si no se dibujan sombras (como se muestra en la captura de pantalla anterior), edite Propiedades/AndroidManifest.xml y agregue el siguiente valor de atributo al <application> elemento :

android:hardwareAccelerated="true"

Esta aplicación básica solo admite la exploración del álbum de fotos. No responde a eventos item-touch ni controla los cambios en los datos subyacentes. Esta funcionalidad se agrega en Extensión del ejemplo RecyclerView.

Cambio del LayoutManager

Debido a la RecyclerViewflexibilidad, es fácil modificar la aplicación para usar un administrador de diseño diferente. En el ejemplo siguiente, se modifica para mostrar el álbum de fotos con un diseño de cuadrícula que se desplaza horizontalmente en lugar de con un diseño lineal vertical. Para ello, la creación de instancias del administrador de diseño se modifica para usar la GridLayoutManager siguiente:

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

Este cambio de código reemplaza el vertical LinearLayoutManager por un GridLayoutManager que presenta una cuadrícula formada por dos filas que se desplazan en la dirección horizontal. Al volver a compilar y ejecutar la aplicación, verá que las fotografías se muestran en una cuadrícula y que el desplazamiento es horizontal en lugar de vertical:

Captura de pantalla de ejemplo de la aplicación con fotos de desplazamiento horizontal en una cuadrícula

Al cambiar solo una línea de código, es posible modificar la aplicación de visualización de fotos para usar un diseño diferente con un comportamiento diferente. Tenga en cuenta que ni el código del adaptador ni el XML de diseño deben modificarse para cambiar el estilo de diseño.

En el tema siguiente, Extensión del ejemplo RecyclerView, esta aplicación de ejemplo básica se extiende para controlar eventos de clic de elemento y actualizar RecyclerView cuando cambia el origen de datos subyacente.