Um exemplo básico de RecyclerView
Para entender como RecyclerView
funciona em um aplicativo típico, este tópico explora um exemplo de código simples que usa RecyclerView
para exibir uma grande coleção de fotos:
O RecyclerViewer usa o CardView para implementar cada item de fotografia no RecyclerView
layout. Devido às vantagens de desempenho do RecyclerView
, este aplicativo de exemplo é capaz de rolar rapidamente por uma grande coleção de fotos sem problemas e sem atrasos perceptíveis.
Um exemplo de fonte de dados
Neste aplicativo de exemplo, uma fonte de dados de "álbum de fotos" (representada pela classe) fornece RecyclerView
o conteúdo do PhotoAlbum
item.
PhotoAlbum
é uma coleção de fotos com legendas; Ao instanciá-lo, você obtém uma coleção pronta de 32 fotos:
PhotoAlbum mPhotoAlbum = new PhotoAlbum ();
Cada instância de foto em PhotoAlbum
expõe propriedades que permitem ler sua ID de recurso de imagem, PhotoID
, e sua cadeia de caracteres de legenda, Caption
. A coleção de fotos é organizada de forma que cada foto possa ser acessada por um indexador. Por exemplo, as seguintes linhas de código acessam a ID do recurso de imagem e a legenda da décima foto da coleção:
int imageId = mPhotoAlbum[9].ImageId;
string caption = mPhotoAlbum[9].Caption;
PhotoAlbum
O também fornece um RandomSwap
método que você pode chamar para trocar a primeira foto da coleção por uma foto escolhida aleatoriamente em outro lugar da coleção:
mPhotoAlbum.RandomSwap ();
Como os detalhes de implementação de PhotoAlbum
não são relevantes para a compreensão RecyclerView
, o PhotoAlbum
código-fonte não é apresentado aqui.
Layout e inicialização
O arquivo de layout, Main.axml, consiste em um único RecyclerView
dentro de um 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>
Observe que você deve usar o nome totalmente qualificado android.support.v7.widget.RecyclerView porque RecyclerView
está empacotado em uma biblioteca de suporte. O OnCreate
método de inicializa esse layout, instancia o adaptador e prepara a fonte de MainActivity
dados subjacente:
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 faz o seguinte:
Instancia a
PhotoAlbum
fonte de dados.Passa a fonte de dados do álbum de fotos para o construtor do adaptador
PhotoAlbumAdapter
(que é definido posteriormente neste guia). Observe que é considerada uma prática recomendada passar a fonte de dados como um parâmetro para o construtor do adaptador.Obtém o
RecyclerView
do layout.Conecta o adaptador à
RecyclerView
instância chamando oRecyclerView
SetAdapter
método conforme mostrado acima.
Gerenciador de layout
Cada item no RecyclerView
é composto por uma CardView
imagem e legenda da foto (os detalhes são abordados na seção View Holder abaixo). A predefinição LinearLayoutManager
é usada para dispor cada CardView
um em um arranjo de rolagem vertical:
mLayoutManager = new LinearLayoutManager (this);
mRecyclerView.SetLayoutManager (mLayoutManager);
Esse código reside no método da OnCreate
atividade principal. O construtor para o gerenciador de layout requer um contexto, portanto, o MainActivity
é passado usando this
como visto acima.
Em vez de usar o predefinido LinearLayoutManager
, você pode conectar um gerenciador de layout personalizado que exibe dois CardView
itens lado a lado, implementando um efeito de animação de virada de página para percorrer a coleção de fotos. Mais adiante neste guia, você verá um exemplo de como modificar o layout trocando por um gerenciador de layout diferente.
Suporte de vista
A classe de suporte de exibição é chamada PhotoViewHolder
de . Cada PhotoViewHolder
instância contém referências ao ImageView
e TextView
de um item de linha associado, que é disposto em um CardView
conforme diagramado aqui:
PhotoViewHolder
deriva de RecyclerView.ViewHolder
e contém propriedades para armazenar referências ao ImageView
e TextView
mostrado no layout acima.
PhotoViewHolder
consiste em duas propriedades e um construtor:
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);
}
}
Neste exemplo de código, o PhotoViewHolder
construtor recebe uma referência à exibição de item pai (o CardView
) que PhotoViewHolder
é encapsulado. Observe que você sempre encaminha a exibição do item pai para o construtor base. O PhotoViewHolder
construtor chama FindViewById
a exibição de item pai para localizar cada uma de suas referências ImageView
de exibição filho e TextView
, armazenando os Image
resultados nas propriedades e Caption
, respectivamente. Posteriormente, o adaptador recupera referências de exibição dessas propriedades quando atualiza as exibições filho com CardView
novos dados.
Para obter mais informações sobre RecyclerView.ViewHolder
o , consulte a referência da classe RecyclerView.ViewHolder.
Adaptador
O adaptador carrega cada RecyclerView
linha com dados para uma fotografia específica. Para uma determinada fotografia na posição de linha P, por exemplo, o adaptador localiza os dados associados na posição P dentro da fonte de dados e copia esses dados para o item de linha na posição P na RecyclerView
coleção. O adaptador usa o suporte de exibição para pesquisar as referências para o ImageView
e TextView
nessa posição para que ele não precise chamar FindViewById
repetidamente essas exibições à medida que o usuário rola pela coleção de fotografias e reutiliza exibições.
No RecyclerViewer, uma classe de adaptador é derivada de RecyclerView.Adapter
para criar PhotoAlbumAdapter
:
public class PhotoAlbumAdapter : RecyclerView.Adapter
{
public PhotoAlbum mPhotoAlbum;
public PhotoAlbumAdapter (PhotoAlbum photoAlbum)
{
mPhotoAlbum = photoAlbum;
}
...
}
O mPhotoAlbum
membro contém a fonte de dados (o álbum de fotos) que é passada para o construtor; o construtor copia o álbum de fotos para essa variável de membro. Os seguintes métodos necessários RecyclerView.Adapter
são implementados:
OnCreateViewHolder
– Instancia o arquivo de layout do item e o suporte da vista.OnBindViewHolder
– Carrega os dados na posição especificada nas vistas cujas referências são armazenadas no suporte de vista fornecido.ItemCount
– Retorna o número de itens na fonte de dados.
O gerenciador de layout chama esses métodos enquanto está posicionando itens dentro do RecyclerView
. A implementação desses métodos é examinada nas seções a seguir.
OnCreateViewHolder
O gerenciador de layout chama OnCreateViewHolder
quando precisa RecyclerView
de um novo suporte de exibição para representar um item. OnCreateViewHolder
Infla a exibição Item do arquivo de layout da exibição e envolve a exibição em uma nova PhotoViewHolder
instância. O PhotoViewHolder
construtor localiza e armazena referências a exibições secundárias no layout, conforme descrito anteriormente em Proprietário da Exibição.
Cada item de linha é representado por um CardView
que contém um ImageView
(para a foto) e um TextView
(para a legenda). Esse layout reside no arquivo 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>
Esse layout representa um único item de linha no RecyclerView
. O OnBindViewHolder
método (descrito abaixo) copia dados da fonte de dados para o ImageView
e TextView
desse layout.
OnCreateViewHolder
infla esse layout para um determinado local de foto no RecyclerView
e instancia uma nova PhotoViewHolder
instância (que localiza e armazena em cache as referências às ImageView
exibições e TextView
filho no layout associado 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;
}
A instância do titular da exibição resultante, vh
, é retornada de volta ao chamador (o gerenciador de layout).
OnBindViewHolder
Quando o gerenciador de layout estiver pronto para exibir uma exibição específica na RecyclerView
área de tela visível do , ele chamará o método do OnBindViewHolder
adaptador para preencher o item na posição de linha especificada com conteúdo da fonte de dados. OnBindViewHolder
Obtém as informações da foto para a posição da linha especificada (o recurso de imagem da foto e a cadeia de caracteres para a legenda da foto) e copia esses dados para os modos de exibição associados. As vistas são localizadas por meio de referências armazenadas no objeto titular da vista (que é passado através do 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;
}
O objeto de suporte de exibição passado deve primeiro ser convertido no tipo de suporte de exibição derivado (nesse caso, PhotoViewHolder
) antes de ser usado.
O adaptador carrega o recurso de imagem na exibição referenciada pela propriedade do proprietário da Image
exibição e copia o texto da legenda para a exibição referenciada pela propriedade do Caption
proprietário da exibição. Isso vincula a exibição associada aos seus dados.
Observe que OnBindViewHolder
é o código que lida diretamente com a estrutura dos dados. Nesse caso, OnBindViewHolder
entende como mapear a posição do RecyclerView
item para seu item de dados associado na fonte de dados. O mapeamento é simples neste caso porque a posição pode ser usada como um índice de matriz no álbum de fotos; no entanto, fontes de dados mais complexas podem exigir código extra para estabelecer esse mapeamento.
ItemCount
O ItemCount
método retorna o número de itens na coleta de dados. No aplicativo visualizador de fotos de exemplo, a contagem de itens é o número de fotos no álbum de fotos:
public override int ItemCount
{
get { return mPhotoAlbum.NumPhotos; }
}
Para obter mais informações sobre RecyclerView.Adapter
, consulte a referência da classe RecyclerView.Adapter.
Juntando as peças
A implementação resultante RecyclerView
para o aplicativo de fotos de exemplo consiste em código que cria a fonte de dados, o gerenciador de MainActivity
layout e o adaptador. MainActivity
cria a mRecyclerView
instância, instancia a origem de dados e o adaptador e conecta o gerenciador de layout e o 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
Localiza e armazena em cache as referências de exibição:
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 as três substituições de método necessárias:
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; }
}
}
Quando esse código é compilado e executado, ele cria o aplicativo básico de exibição de fotos, conforme mostrado nas seguintes capturas de tela:
Se as sombras não estiverem sendo desenhadas (como visto na captura de tela acima), edite Propriedades/AndroidManifest.xml e adicione a seguinte configuração de atributo ao <application>
elemento:
android:hardwareAccelerated="true"
Este aplicativo básico suporta apenas a navegação no álbum de fotos. Ele não responde a eventos de toque no item, nem lida com alterações nos dados subjacentes. Essa funcionalidade é adicionada em Estendendo o exemplo RecyclerView.
Alterando o LayoutManager
Devido à flexibilidade do , é fácil modificar o aplicativo para usar um gerenciador de RecyclerView
layout diferente. No exemplo a seguir, ele é modificado para exibir o álbum de fotos com um layout de grade que rola horizontalmente em vez de com um layout linear vertical. Para fazer isso, a instanciação do gerenciador de layout é modificada para usar o GridLayoutManager
seguinte:
mLayoutManager = new GridLayoutManager(this, 2, GridLayoutManager.Horizontal, false);
Essa alteração de código substitui a vertical LinearLayoutManager
por uma GridLayoutManager
que apresenta uma grade composta por duas linhas que rolam na direção horizontal. Ao compilar e executar o aplicativo novamente, você verá que as fotografias são exibidas em uma grade e que a rolagem é horizontal em vez de vertical:
Ao alterar apenas uma linha de código, é possível modificar o aplicativo de visualização de fotos para usar um layout diferente com comportamento diferente. Observe que nem o código do adaptador nem o XML do layout tiveram que ser modificados para alterar o estilo do layout.
No próximo tópico, Estendendo o exemplo RecyclerView, esse aplicativo de exemplo básico é estendido para lidar com eventos de clique de item e atualizar RecyclerView
quando a fonte de dados subjacente é alterada.