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:
RecyclerViewer usa CardView para implementar cada elemento de fotografía en el RecyclerView
diseño. Debido a las ventajas de RecyclerView
rendimiento, 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:
Crea una instancia del
PhotoAlbum
origen de datos.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.Obtiene del
RecyclerView
diseño.Conecta el adaptador a la
RecyclerView
instancia llamando alRecyclerView
SetAdapter
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í:
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 () CardView
que 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 TextView
ImageView
, almacenando los resultados en las Image
propiedades yCaption
, respectivamente. Posteriormente, el adaptador recupera las referencias de vista de estas propiedades cuando actualiza estas CardView
vistas 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 ImageView
TextView
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.
OnCreateViewHolder
infla 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. OnBindViewHolder
obtiene 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:
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 RecyclerView
flexibilidad, 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:
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.