====== Crie listas com RecyclerView ======
Em aplicativos [[Android]], é comum criar telas com listagens de diversas formas possíveis: horizontalmente, verticalmente, em forma de grade, entre outros exemplos. Existem casos que a quantidade de itens é **tão grande** que o aplicativo demora **vários segundos** para renderizar-los, causando **desconforto** no usuário. Dessa forma, entra em cena o //**RecyclerView**//, componente padrão de //layout// de listagens do [[Android Studio]] para uso no desenvolvimento nativo de aplicativos [[Android]], o qual utiliza itens "**recicláveis**" na respectiva //[[https://developer.android.com/reference/android/view/View|View]]// a ser desenvolvida.
O //**RecyclerView**// funciona renderizando **somente os itens** da lista **que aparecerão** na tela do celular, deixando todos os outros descarregados e assim "**reciclando**" a listagem. O intuito é poder carregar a quantidade suficiente de itens sem que isso interfira na **experiência do usuário** durante o uso do //app//. Apesar da boa intenção, a configuração de um //**RecyclerView**// pode **não ser tão intuitiva** para iniciantes.
----
===== Estrutura =====
O //**RecyclerView**// é estruturado em quatro partes:
* Administrador do //layout// (//[[https://developer.android.com/reference/android/support/v7/widget/RecyclerView.LayoutManager|Layout Manager]]//);
* Adaptador de itens da lista (//[[https://developer.android.com/reference/android/widget/Adapter|Adapter]]//);
* Apoio da //View// (//[[https://developer.android.com/reference/android/support/v7/widget/RecyclerView.ViewHolder|ViewHolder]]//);
* //**RecyclerView**// propriamente dito.
Todas as quatro partes conversam-se entre si, portanto, deve-se ter em mente a **visualização da listagem** antes da configuração. A harmonia entre as partes produz um //design// perfeito para o aplicativo.
==== LayoutManager ====
O //LayoutManager// é a parte que dita o **visual da listagem** no momento de sua renderização, e é atribuído ao //**RecyclerView**// no momento da configuração deste componente. Por exemplo, caso se utilize um //LayoutManager// do tipo //[[https://developer.android.com/reference/android/support/v7/widget/LinearLayoutManager|LinearLayoutManager]]//, pode-se criar listas **lineares** tanto verticais quanto horizontais, sendo essa orientação definida no momento de sua instanciação. Por outro lado, há a existência do //[[https://developer.android.com/reference/android/support/v7/widget/GridLayoutManager|GridLayoutManager]]//, que organiza a lista em forma de **grade**, semelhante a aplicativos padrão de fotos. Por conta do //GridLayoutManager// criar uma listagem em grade de forma que **todos os itens têm a mesma largura e altura**, há momentos que se gera **desconforto** pela informação não encaixar perfeitamente nos itens. Para evitar esse efeito, pode-se utilizar o //[[https://developer.android.com/reference/android/support/v7/widget/StaggeredGridLayoutManager|StaggeredGridLayoutManager]]//, que **adapta** a altura do item de acordo com o item presente em seu interior e permite um **desnível** entre os itens laterais, possibilitando um //design// mais **limpo e leve**, assim como é no [[https://keep.google.com|Google Keep]].
==== Adapter ====
O //Adapter// trata da **forma em que serão organizados** os itens da lista a ser exibida, sendo responsável por dizer **quantos itens** aparecerão na lista, como será o //layout// dos itens a serem apresentados e qual será a **lógica de apresentação** de cada item específico. Geralmente, o programador deve criar uma **nova classe** para ser o //Adapter// de seu //**RecyclerView**//, e essa nova classe deve herdar de //[[https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter|RecyclerView.Adapter]]//. Dentro da classe, deve-se implementar **obrigatoriamente** os métodos //onCreateViewHolder//, //onBindViewHolder// e //getItemCount//. Fica clara a relação do //Adapter// com o //ViewHolder// justamente pelo nome dos métodos mencionados.
=== onCreateViewHolder ===
Esse método trata do **momento da criação** do //ViewHolder// conectado ao //Adapter//, o qual carregará consigo o //layout// XML do item da lista. Esse //layout// será usado na construção de um objeto do tipo //View// para utilizar posteriormente na construção e retorno do //ViewHolder// citado. Em resumo: será escolhido um //layout// específico para representação dos itens da lista e este será conectado ao //ViewHolder// atrelado a cada item da lista.
=== onBindViewHolder ===
Como o próprio nome sugere, esse método tratará o momento que **um item** da lista **aparecer no aplicativo**. No momento que o item em questão for **vinculado** (do inglês //bind//) à lista, esse método será chamado e executado antes da apresentação dele.
=== getItemCount ===
Seguindo a intuitividade, esse método deve **retornar o tamanho da lista** a ser renderizada. Em praticamente todas as situações, será retornado o tamanho da lista de itens dentro do //Adapter//.
==== ViewHolder ====
A classe //ViewHolder// será responsável por **identificar os componentes de //layout//** de cada item da lista (//TextViews//, //ImageViews// e //Buttons//, por exemplo). Essa classe, que deve **herdar obrigatoriamente** de //[[https://developer.android.com/reference/android/support/v7/widget/RecyclerView.ViewHolder|RecyclerView.ViewHolder]]//, deve também obrigatoriamente implementar **seu construtor**, que em praticamente todas as vezes será aplicando o método //findViewById// em seus objetos de componente de //layout// locais. Como seu próprio nome sugere, o //ViewHolder// será um apoio para a //View// atrelada ao //layout// do item da lista, este presente como parâmetro no método construtor daquele. Posteriormente, o //ViewHolder// será usado como meio-termo para endereçar e modificar os componentes do //layout// do item da lista através dos métodos implementados no //Adapter//.
==== Componente RecyclerView ====
O //**RecyclerView**// em si será o objeto que representará a lista a ser apresentada no aplicativo. No //layout// XML da //Activity// ou do //Fragment//, deverá ser adicionado o componente de //layout// referente ao //**RecyclerView**//, além do próprio objeto dentro do código Java. Programaticamente, o //LayoutManager// e o //Adapter// serão vinculados ao //**RecyclerView**// durante sua configuração. Internamente ao //Adapter//, o //ViewHolder// estará atuando na identificação dos componentes de //layout// de cada item da lista, tratando-os conforme configurado em cada método implementado no //Adapter//. É assim que se dá a configuração e harmonia entre os componentes do //**RecyclerView**//.
----
===== Exemplo de implementação =====
Numa situação de desenvolvimento de um aplicativo, é quase impossível não se deparar com um momento de criação de uma lista, ainda mais quando se trata de muito itens a serem mostrados na tela do usuário, como é o caso da maior parte das redes sociais. Neste exemplo, será mostrado uma situação de criação de uma lista simples, com alguns campos de texto por item.
==== Criando o RecyclerView dentro de sua Activity ou Fragment ====
Com um projeto [[Android]] criado, ao criar uma nova //Activity//, teremos o código //default// abaixo dentro da classe java no pacote especificado.
package com.exemplo.recyclerview;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
Além disso, também será criado o arquivo XML com o código //default// abaixo dentro da pasta **res** > **layout**, o qual está "conectado" com o arquivo java acima descrito.
Ao abrir o arquivo XML no [[Android Studio]], temos a tela a seguir.
{{ :recyclerview-example-1.png?direct |}}
Para fins didáticos, excluiremos o //TextView// presente no //layout// e adicionaremos o //**RecyclerView**// ao //layout//. Para isso, basta selecionar o componente //**RecyclerView**// em //Palette// e arrastar para a tela branca.
{{ :recyclerview-example-2-edit.png?direct |}}
Será aberto um aviso para confirmar a importação da biblioteca referente ao //**RecyclerView**//. Basta clicar em **OK** para continuar.
{{ :recyclerview-example-3.png?direct |}}
Dessa forma, o //**RecyclerView**// será importado ao projeto e adicionado ao seu //layout// que está conectado à sua //Activity//. Conectando as //constraints// às laterais de sua tela branca e inserindo a //string// **recyclerViewExemplo** como //id// do //**RecyclerView**// adicionado, teremos como resultado a imagem abaixo.
{{ :recyclerview-example-4.png?direct |}}
Como resultado, o código XML referente ao //layout// será o apresentado a seguir.
==== Instanciando o LayoutManager e vinculando-o ao RecyclerView ====
Nesse passo, primeiramente iremos referenciar o //**RecyclerView**// no código java através da classe representativa do componente e do método //findViewById//.
package com.exemplo.recyclerview;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.RecyclerView;
public class MainActivity extends AppCompatActivity {
//Variável global para referenciar o RecyclerView da interface
private RecyclerView recyclerViewExemplo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Conectando a classe representativa com o componente de layout
recyclerViewExemplo = findViewById(R.id.recyclerViewExemplo);
}
}
Posteriormente, iremos instanciar o //LayoutManager// configurando-o da forma que preferirmos e inserindo no //**RecyclerView**//. Nesse exemplo, configuraremos o //LayoutManager// como sendo do tipo //LinearLayoutManager// com orientação vertical.
package com.exemplo.recyclerview;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
public class MainActivity extends AppCompatActivity {
//Variável global para referenciar o RecyclerView da interface
private RecyclerView recyclerViewExemplo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Conectando a classe representativa com o componente de layout
recyclerViewExemplo = findViewById(R.id.recyclerViewExemplo);
//Configurando o LayoutManager e inserindo a configuração em nosso RecyclerView
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(
this,
LinearLayoutManager.VERTICAL,
false
);
recyclerViewExemplo.setLayoutManager(layoutManager);
}
}
==== Definindo o ViewHolder ====
O //ViewHolder//, com o papel de apoiador da //View//, será uma nova classe auxiliar a ser criada. Primeiramente, para que um //ViewHolder// faça sentido, precisamos criar um //layout// referente aos itens da lista, tal qual será a base para cada um a ser apresentado.
Primeiramente, vá até **res** > **layout**, clique com botão direito na pasta e vá em **New** > **Layout resource file**. Uma janela será aberta. **Cuidado**: isso **deve** ser feito na pasta **layout**.
{{ :recyclerview-example-5.png?direct |}}
Na janela aberta, escolha um nome para o seu arquivo de //layout//. Nesse exemplo, será escolhido o nome //adapter_itens// por questão de didática, mas pode ser escolhido qualquer nome. Em //Root element//, você pode escolher qualquer //layout// que preferir. Para que o exemplo se torne mais fácil, iremos escolher o //ConstraintLayout//.
{{ :recyclerview-example-6.png?direct |}}
Após criar o arquivo de //layout//, crie o seu próprio //layout// para os itens de sua lista. Você pode pegar um pouco de inspiração na imagem abaixo, mas sinta-se livre para criar algo que seja agradável.
**Lembre-se**: o //layout// mais **externo** deve ter o atributo //layout_height// com o valor **//wrap_content//**. Caso não seja feita essa verificação, há possibilidade dos itens possuírem um tamanho muito grande para o tamanho da tela.
**Dica**: utilizar //LinearLayout// ao invés de //ConstraintLayout// traz resultados melhores nessa parte da configuração do //**RecyclerView**//, mas, como dito, por questões didáticas, será mantido o uso do segundo.
{{ ::recyclerview-example-7.png?direct |}}
O código XML referente ao //layout// desenvolvido acima está mostrado abaixo.
Após criar o //layout// referente a cada item da lista, será criada a classe auxiliar referente ao //ViewHolder//. Para isso, vá em **java** > **nome.do.seu.pacote**, e, com o botão direito, vá em **New** > **Java Class**.
{{ :recyclerview-example-8.png?direct |}}
Na janela aberta, coloque um nome para o seu //ViewHolder//. Neste exemplo, será usado o nome //MyViewHolder//, mas pode ser utilizado o nome que preferir.
{{ :recyclerview-example-9.png?direct |}}
Ao clicar em **OK**, a classe java será criada com o código abaixo.
package com.exemplo.recyclerview;
public class MyViewHolder {
}
Essa classe deverá extender de //RecyclerView.ViewHolder//. Ao adicionar essa herança, o código resultante será o abaixo.
package com.exemplo.recyclerview;
import android.support.v7.widget.RecyclerView;
public class MyViewHolder extends RecyclerView.ViewHolder {
}
Ao adicionar essa superclasse à classe, pode ser reparado que a declaração da classe fica grifada em vermelho. Isso se deve ao fato que se tem a obrigatoriedade de declarar um construtor para essa classe, por conta que essa classe deverá referenciar, dentro de seu construtor, cada um dos componentes de //layout// inseridos no //layout// criado nos passos anteriores. Para que isso seja resolvido, clique na lâmpada vermelha que aparece à esquerda, e selecione a opção **//Create constructor matching super//**.
{{ :recyclerview-example-10.png?direct |}}
O seu código terá como resultado o abaixo.
package com.exemplo.recyclerview;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.View;
public class MyViewHolder extends RecyclerView.ViewHolder {
public MyViewHolder(@NonNull View itemView) {
super(itemView);
}
}
Agora, dentro do construtor, referencie todos os componentes de //layout// que você inseriu no //layout// criado anteriormente. O código abaixo será referente ao //layout// sugerido anteriormente.
package com.exemplo.recyclerview;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView textNumeroItem, textDescricaoItem, textData;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
textNumeroItem = itemView.findViewById(R.id.textNumeroItem);
textDescricaoItem = itemView.findViewById(R.id.textDescricaoItem);
textData = itemView.findViewById(R.id.textData);
}
}
**Obs**: devemos referenciar através do objeto //itemView// que é passado por parâmetro ao construtor do //ViewHolder//. Isso se deve por conta de que somente conseguiremos referenciar os componentes de //layout// que estão "dentro" do //itemView//, o qual é do tipo //View//. Por isso que o //ViewHolder// é, de fato, um apoio da //View//. Além disso, em alguns passos adiante, na declaração do //Adapter//, devemos escolher de forma correta o //layout// a ser inserido na //View// a ser criada, para que não haja erros dentro do //ViewHolder// na hora de referenciar os componentes de //layout//.
==== Configurando o Adapter e vinculando o ViewHolder a ele ====
Para criar o //Adapter//, devemos criar uma nova classe java e fazê-la herdar de //RecyclerView.Adapter//. Neste exemplo, deve-se criar uma classe com nome //AdapterExemplo//, e no lugar de //ViewHolder// da classe que será herdada, será usado //MyViewHolder//.
Primeiramente, vá até **java** > **nome.do.seu.pacote**, clique com o botão direito, vá até **New** > **Java Class**.
{{ :recyclerview-example-11.png?direct |}}
No nome da classe, coloque o nome //AdapterExemplo// e clique em **OK**.
{{ :recyclerview-example-12.png?direct |}}
O código estará assim no momento que a classe for criada.
package com.exemplo.recyclerview;
public class AdapterExemplo {
}
Agora, é necessário herdar de //RecyclerView.Adapter//. Não esqueça de utilizar a sua classe //ViewHolder// criada anteriormente. Neste exemplo, trata-se da //MyViewHolder//.
package com.exemplo.recyclerview;
import android.support.v7.widget.RecyclerView;
public class AdapterExemplo extends RecyclerView.Adapter {
}
Nesse momento, pode-se reparar que a declaração da classe está grifada em vermelho pelo próprio [[Android Studio]]. Isso ocorre porque é obrigatória a declaração dos métodos //onCreateViewHolder//, //onBindViewHolder// e //getItemCount//. Para isso, basta clicar uma vez em cima da declaração da classe, esperar a lâmpada vermelha aparecer, clicar nela e escolher a opção //**Implement methods**//.
{{ :recyclerview-example-13.png?direct |}}
Após isso, apenas selecione **OK**. Os métodos serão implementados automaticamente.
{{ :recyclerview-example-14.png?direct |}}
Após isso, a classe estará dessa maneira.
package com.exemplo.recyclerview;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup;
public class AdapterExemplo extends RecyclerView.Adapter {
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
return null;
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder myViewHolder, int i) {
}
@Override
public int getItemCount() {
return 0;
}
}
Para continuar a configuração do //Adapter//, precisamos criar uma classe que represente cada item da lista a ser apresentada ao usuário. Neste exemplo, será criada uma classe generalista, sem motivações específicas. No entanto, numa aplicação real, poderia ser uma classe sobre produtos, usuários, ofertas, etc. Para isso, vá novamente em **java** > **nome.do.seu.pacote**, clique com o botão direito, vá até **New** > **Java Class**. Aqui, o nome da classe será somente //Item//.
Após isso, serão adicionadas três //strings// representando o conteúdo presente em cada //TextView// criado no //layout// exemplo construído anteriormente. Caso você possua imagens, você pode guardar o valor de seu //id// numa variável do tipo //int// ou a //url// dela numa variável do tipo //string// ou mesmo do tipo //[[https://developer.android.com/reference/java/net/URI|Uri]]//.
O código resultante, para este exemplo, está representado abaixo. Repare que já foram adicionados os //getters// e os //setters//, além de seu construtor.
package com.exemplo.recyclerview;
public class Item {
private String textNumeroItem;
private String textDescricaoItem;
private String textData;
public Item(String textNumeroItem, String textDescricaoItem, String textData) {
this.textNumeroItem = textNumeroItem;
this.textDescricaoItem = textDescricaoItem;
this.textData = textData;
}
public String getTextNumeroItem() {
return textNumeroItem;
}
public void setTextNumeroItem(String textNumeroItem) {
this.textNumeroItem = textNumeroItem;
}
public String getTextDescricaoItem() {
return textDescricaoItem;
}
public void setTextDescricaoItem(String textDescricaoItem) {
this.textDescricaoItem = textDescricaoItem;
}
public String getTextData() {
return textData;
}
public void setTextData(String textData) {
this.textData = textData;
}
}
Após criar a classe base para cada item da lista, voltaremos ao //Adapter// e criaremos como atributo dentro dele uma lista de //Item//, além de um construtor que recebe como atributo também uma lista de //Item//. O construtor, nesse caso, serve para que, durante a configuração do //**RecyclerView**//, o //Adapter// saiba quais itens serão apresentados na tela do aplicativo.
package com.exemplo.recyclerview;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup;
import java.util.List;
public class AdapterExemplo extends RecyclerView.Adapter {
private List- listaItens;
public AdapterExemplo(List
- listaItens) {
this.listaItens = listaItens;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
return null;
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder myViewHolder, int i) {
}
@Override
public int getItemCount() {
return 0;
}
}
O primeiro método que podemos configurar é o //getItemCount//, que retornará ao //**RecyclerView**// o número de itens da lista a ser apresentada. No nosso exemplo, será justamente o tamanho da lista que o //Adapter// possui como atributo.
package com.exemplo.recyclerview;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup;
import java.util.List;
public class AdapterExemplo extends RecyclerView.Adapter {
private List- listaItens;
public AdapterExemplo(List
- listaItens) {
this.listaItens = listaItens;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
return null;
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder myViewHolder, int i) {
}
@Override
public int getItemCount() {
return listaItens.size();
}
}
O próximo método a ser configurado é o //onCreateViewHolder//, que deverá inflar (leia-se criar e apresentar ao usuário) a //View// referente a cada item da lista e retornar ao //ViewHolder//, para que este possa referenciar cada componente de //layout// daquele e configurar conforme o conteúdo de cada objeto presente na lista //listaItens//.
package com.exemplo.recyclerview;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.List;
public class AdapterExemplo extends RecyclerView.Adapter {
private List- listaItens;
public AdapterExemplo(List
- listaItens) {
this.listaItens = listaItens;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.adapter_itens, viewGroup, false);
return new MyViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder myViewHolder, int i) {
}
@Override
public int getItemCount() {
return listaItens.size();
}
}
Apesar de parecer bruxaria, é possível explicar o código surgido das trevas dentro do método. A ideia é **inflar** a //View// usando a classe //[[https://developer.android.com/reference/android/view/LayoutInflater|LayoutInflater]]//, dentro de um //[[https://developer.android.com/reference/android/content/Context|Context]]// o qual ele deve aparecer. Depois de dito onde deve ser inflado, deve-se indicar **qual é a fonte** que "alimentará" a //View//, que é justamente o //layout// que foi criado anteriormente (e indicado pelo seu //id//, //R.layout.adapter_itens//). O atributo do tipo //[[https://developer.android.com/reference/android/view/ViewGroup|ViewGroup]]// é algo como um **//container// de objetos** do tipo //View//, o qual servirá de base para apresentar todas as //View// na tela do usuário. Por fim, o último atributo booleano com valor //false// indica que a hierarquia inflada **não será vinculada** ao parâmetro raiz.
**Obs**: a classe //Context// diz **qual é o contexto** no momento da execução de seu aplicativo, e esse contexto muda a **cada vez que é mudada a //Activity// atual**. Uma forma fácil, porém incorreta, de entender esse conceito é pensar que cada //Activity// possui seu //Context//, então se caso precisamos utilizar o //Context// atual para algo, devemos entender que o código deseja entender em qual //Activity// estamos. Esse pensamento só é incorreto porque a classe //Activity//, na verdade, herda da classe //Context//.
Finalmente, o último passo para a configuração do //Adapter// é implementar o método //onBindViewHolder//. Esse método deverá encontrar qual é o item correspondente a ser ligado à lista visível ao usuário e referenciar cada conteúdo do objeto a cada componente de //layout// presente na //View//.
package com.exemplo.recyclerview;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.List;
public class AdapterExemplo extends RecyclerView.Adapter {
private List- listaItens;
public AdapterExemplo(List
- listaItens) {
this.listaItens = listaItens;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.adapter_itens, viewGroup, false);
return new MyViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder myViewHolder, int i) {
Item item = listaItens.get(i);
myViewHolder.textNumeroItem.setText(item.getTextNumeroItem());
myViewHolder.textDescricaoItem.setText(item.getTextDescricaoItem());
myViewHolder.textData.setText(item.getTextData());
}
@Override
public int getItemCount() {
return listaItens.size();
}
}
Aqui, espera-se que não haja alguma feitiçaria dentro do método. É possível existir, mas fica por conta e risco do programador.
==== Concluindo a configuração do RecyclerView e teste ====
Neste momento, as classes //Adapter// e //ViewHolder// estão configuradas. Agora, precisaremos voltar para a //Activity// principal de nosso projeto e configurar, finalmente, o tão amado //**RecyclerView**//. Primeiramente, será preciso de um banco de dados de itens para serem apresentados na lista. Numa aplicação real, essa lista será obtida através de um banco de dados na nuvem ou baixados através de uma API presente num servidor da aplicação. Como aqui se trata de um exemplo, será criado um banco de dados //hardcoded//.
package com.exemplo.recyclerview;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
//Variável global para referenciar o RecyclerView da interface
private RecyclerView recyclerViewExemplo;
//Lista de itens a serem apresentadas na lista
private List- listaItens = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Conectando a classe representativa com o componente de layout
recyclerViewExemplo = findViewById(R.id.recyclerViewExemplo);
//Configurando o LayoutManager e inserindo a configuração em nosso RecyclerView
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(
this,
LinearLayoutManager.VERTICAL,
false
);
recyclerViewExemplo.setLayoutManager(layoutManager);
criarItens();
}
//Criando base de dados
private void criarItens(){
Item item;
item = new Item(
"1",
"Potato são potatos.",
"04/10/2019"
);
listaItens.add(item);
item = new Item(
"2",
"Talvez potatos sejam diferentes.",
"05/04/2019"
);
listaItens.add(item);
item = new Item(
"3",
"Você disse potato?",
"15/06/2019"
);
listaItens.add(item);
item = new Item(
"4",
"Adoro dizer potatos.",
"08/01/2019"
);
listaItens.add(item);
}
}
Agora, devemos instanciar um objeto do tipo //AdapterExemplo// que criamos na seção anterior, inserindo como atributo de seu construtor a lista //listaItens//. Após a instanciação, podemos vincular o //Adapter// ao nosso //**RecyclerView**//.
package com.exemplo.recyclerview;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
//Variável global para referenciar o RecyclerView da interface
private RecyclerView recyclerViewExemplo;
//Lista de itens a serem apresentadas na lista
private List- listaItens = new ArrayList<>();
//Adapter a ser utilizado no RecyclerView
private AdapterExemplo adapterExemplo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Conectando a classe representativa com o componente de layout
recyclerViewExemplo = findViewById(R.id.recyclerViewExemplo);
//Configurando o LayoutManager e inserindo a configuração em nosso RecyclerView
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(
this,
LinearLayoutManager.VERTICAL,
false
);
recyclerViewExemplo.setLayoutManager(layoutManager);
criarItens();
//Instanciando o Adapter e vinculando-o ao RecyclerView
adapterExemplo = new AdapterExemplo(listaItens);
recyclerViewExemplo.setAdapter(adapterExemplo);
}
//Criando base de dados
private void criarItens(){
Item item;
item = new Item(
"1",
"Potato são potatos.",
"04/10/2019"
);
listaItens.add(item);
item = new Item(
"2",
"Talvez potatos sejam diferentes.",
"05/04/2019"
);
listaItens.add(item);
item = new Item(
"3",
"Você disse potato?",
"15/06/2019"
);
listaItens.add(item);
item = new Item(
"4",
"Adoro dizer potatos.",
"08/01/2019"
);
listaItens.add(item);
}
}
Ao executar o aplicativo, podemos ver o resultado de toda a configuração realizada.
{{ :recyclerview-example-15.png?direct |}}
Pode-se adicionar mais itens até que seja necessário rolar a lista para baixo. **Não importa** a quantidade de itens que seja colocado, mesmo sendo **10**, **100** ou **1000**: o aplicativo executará **sem travamentos**.
{{ :recyclerview-example-16.png?direct |}}
----
===== Complementos =====
==== Evento de clique ====
Além da configuração de um //**RecyclerView**// para mostrar itens na tela do usuário, pode-se também configurar eventos de clique em cada item da lista. Isso é muito útil para aplicativos de redes sociais, //marketplaces//, entre vários outros exemplos.
Para isso, deve-se primeiro incluir essa classe dentro de seu projeto.
package com.exemplo.recyclerview;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AdapterView;
/**
* Created by Jamilton on 01/11/2017.
* RecyclerView não possui o método OnItemClickListener para identificar o clique do item.
* Você precisa escrever sua própria classe que se estende RecyclerView.OnItemTouchListener.
*/
public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
private OnItemClickListener mListener;
GestureDetector mGestureDetector;
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
View childView = rv.findChildViewUnder(e.getX(), e.getY());
if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
mListener.onItemClick(childView, rv.getChildAdapterPosition(childView));
return true;
}
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
public interface OnItemClickListener extends AdapterView.OnItemClickListener {
public void onItemClick(View view, int position);
public void onLongItemClick(View view, int position);
}
public RecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) {
mListener = listener;
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
@Override
public void onLongPress(MotionEvent e) {
View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (child != null && mListener != null) {
mListener.onLongItemClick(child, recyclerView.getChildAdapterPosition(child));
}
}
});
}
}
Após isso, dentro de sua //Activity//, configure o //**RecyclerView**// com o pedaço de código abaixo.
recyclerViewExemplo.addOnItemTouchListener(new RecyclerItemClickListener(
this,
recyclerViewExemplo,
new RecyclerItemClickListener.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
Item item = listaItens.get(position);
Toast.makeText(
MainActivity.this,
"Você clicou no item número " + item.getTextNumeroItem(),
Toast.LENGTH_SHORT
).show();
}
@Override
public void onLongItemClick(View view, int position) {
}
@Override
public void onItemClick(AdapterView> parent, View view, int position, long id) {
}
}
));
Após essa configuração, a cada vez que clicar em um item da lista, será mostrado uma mensagem com o atributo "número" do item.
==== Animações ====
É possível criar animações no momento que cada item da lista é carregado na tela do usuário. Você pode implementar isso [[https://medium.com/better-programming/android-recyclerview-with-beautiful-animations-5e9b34dbb0fa|seguindo esse tutorial]].
==== Exemplos ====
* Um //chat// entre duas pessoas pode (e deve) ser implementado utilizando um //**RecyclerView**//. A ideia é que, no método //onCreateViewHolder//, seja feito uma verificação e decidido se o balão será referente ao usuário que utiliza o aplicativo (balão verde) ou ao outro usuário (balão branco), mudando o //layout// base em cada situação.
{{ :recyclerview-example-17.png?direct |}}
* Um aplicativo de gerenciamento de despesas **tem obrigação** de ter um histórico de gastos. Um exemplo disso é o aplicativo [[https://www.organizze.com.br/|Organizze]], que consegue mostrar de forma clara todos os seus gastos. Ao desenvolver um aplicativo semelhante que necessita desse histórico, o uso do //**RecyclerView**// é uma boa opção.
{{ :recyclerview-example-18.png?direct |}}
----
===== Referências externas =====
Você pode acessar o código completo do exemplo desenvolvido aqui no [[https://github.com/ADA-EC/Wiki|repositório da ADA]] no GitHub. Outros //links// utilizados como base de desenvolvimento desse artigo estão elencados abaixo.
* [[https://www.udemy.com/course/curso-de-desenvolvimento-android-oreo/|Udemy | Desenvolvimento Android Completo - Aprenda a criar 18 Apps]]
* [[https://medium.com/better-programming/android-recyclerview-with-beautiful-animations-5e9b34dbb0fa|Medium | Android RecyclerView with beautiful animations]]
* [[https://developer.android.com/reference/androidx/recyclerview/widget/RecyclerView.html|Android Developers | RecyclerView documentation]]
* [[https://developer.android.com/guide/topics/ui/layout/recyclerview|Android Developers | Create a List with RecyclerView]]
* [[https://developer.android.com/reference/android/support/v7/widget/RecyclerView.LayoutManager|Android Developers | RecyclerView.LayoutManager]]
* [[https://developer.android.com/reference/android/widget/Adapter|Android Developers | RecyclerView.Adapter]]
* [[https://developer.android.com/reference/android/support/v7/widget/RecyclerView.ViewHolder|Android Developers | RecyclerView.ViewHolder]]
* [[https://developer.android.com/reference/android/view/ViewGroup|Android Developers | ViewGroup]]
* [[https://developer.android.com/reference/android/view/View|Android Developers | View]]
* [[https://developer.android.com/reference/android/support/v7/widget/LinearLayoutManager|Android Developers | LinearLayoutManager]]
* [[https://developer.android.com/reference/android/support/v7/widget/GridLayoutManager|Android Developers | GridLayoutManager]]
* [[https://developer.android.com/reference/android/support/v7/widget/StaggeredGridLayoutManager|Android Developers | StaggeredGridLayoutManager]]
* [[https://developer.android.com/reference/android/view/LayoutInflater|Android Developers | LayoutInflater]]
* [[https://developer.android.com/reference/android/content/Context|Android Developers | Context]]
* [[https://developer.android.com/reference/java/net/URI|Android Developers | URI]]