Compartilhar via


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:

Duas capturas de tela de um aplicativo RecyclerView que usa CardViews para exibir 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:

  1. Instancia a PhotoAlbum fonte de dados.

  2. 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.

  3. Obtém o RecyclerView do layout.

  4. Conecta o adaptador à RecyclerView instância chamando o RecyclerView 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 PhotoViewHolderde . 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:

Diagrama de CardView contendo um ImageView e um TextView

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 CardViewnovos dados.

Para obter mais informações sobre RecyclerView.ViewHoldero , 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:

Duas capturas de tela do aplicativo de visualização de fotos com cartões de fotos de rolagem vertical

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 RecyclerViewlayout 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:

Exemplo de captura de tela do aplicativo com fotos de rolagem horizontal em uma grade

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.