Neste tutorial, vamos usar um CustomAdapter que preenche as linhas personalizadas do Android ListView com um ArrayList
. Além disso, para aprimorar a experiência do usuário, animaremos o ListView durante o rolamento.
Visão Geral do Adaptador Personalizado do Android ListView
O adaptador mais simples para popular uma visualização a partir de um ArrayList é o ArrayAdapter
. É isso que implementaremos neste tutorial. Existem outros adaptadores também, como o CursorAdapter
, que se vincula diretamente a um conjunto de resultados de um Banco de Dados SQLite local e usa um Cursor como fonte de dados.
Reciclagem de Linhas
Conforme um ListView é instanciado e as linhas são preenchidas, a altura total da lista é ocupada. Depois disso, nenhum novo item de linha é criado na memória. Conforme o usuário rola pela lista, os itens que saem da tela são mantidos na memória para uso posterior, e cada nova linha que entra na tela reutiliza uma linha mais antiga mantida na memória.
Criando um modelo de visualização
Vamos criar um layout xml que apresenta os itens em uma linha de forma personalizada. row_item.xml
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:text="Marshmallow"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@android:color/black" />
<TextView
android:id="@+id/type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/name"
android:layout_marginTop="5dp"
android:text="Android 6.0"
android:textColor="@android:color/black" />
<ImageView
android:id="@+id/item_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:src="@android:drawable/ic_dialog_info" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true">
<TextView
android:id="@+id/version_heading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="API: "
android:textColor="@android:color/black"
android:textStyle="bold" />
<TextView
android:id="@+id/version_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="23"
android:textAppearance="?android:attr/textAppearanceButton"
android:textColor="@android:color/black"
android:textStyle="bold" />
</LinearLayout>
</RelativeLayout>
Neste tutorial, iremos construir uma aplicação que consiste em uma lista de linhas exibindo descrições de texto e um ícone de informação. Ao clicar na linha, será exibido um SnackBar com os elementos de texto dessa linha. Ao clicar na informação, será exibido um SnackBar com informações específicas dessa linha.
Estrutura do Projeto
Código
Estamos criando um ListView personalizado ao subclassear ArrayAdapter com o DataModel como objeto. getView() é o método que retorna a visualização real usada como uma linha dentro do ListView em uma posição específica. O content_main.xml
contém o ListView conforme mostrado abaixo. content_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="https://schemas.android.com/apk/res-auto"
tools:context="com.journaldev.customlistview.MainActivity"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/activity_main">
<ListView
android:id="@+id/list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</RelativeLayout>
O modelo de dados contido no ArrayList é mostrado abaixo. DataModel.java
public class DataModel {
String name;
String type;
String version_number;
String feature;
public DataModel(String name, String type, String version_number, String feature ) {
this.name=name;
this.type=type;
this.version_number=version_number;
this.feature=feature;
}
public String getName() {
return name;
}
public String getType() {
return type;
}
public String getVersion_number() {
return version_number;
}
public String getFeature() {
return feature;
}
}
O CustomAdapter que popula o DataModel na ListView é mostrado abaixo. CustomAdapter.java
public class CustomAdapter extends ArrayAdapter implements View.OnClickListener{
private ArrayList dataSet;
Context mContext;
// Cache de visualização
private static class ViewHolder {
TextView txtName;
TextView txtType;
TextView txtVersion;
ImageView info;
}
public CustomAdapter(ArrayList data, Context context) {
super(context, R.layout.row_item, data);
this.dataSet = data;
this.mContext=context;
}
@Override
public void onClick(View v) {
int position=(Integer) v.getTag();
Object object= getItem(position);
DataModel dataModel=(DataModel)object;
switch (v.getId())
{
case R.id.item_info:
Snackbar.make(v, "Release date " +dataModel.getFeature(), Snackbar.LENGTH_LONG)
.setAction("No action", null).show();
break;
}
}
private int lastPosition = -1;
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// Obter o item de dados para esta posição
DataModel dataModel = getItem(position);
// Verificar se uma visualização existente está sendo reutilizada, caso contrário, inflar a visualização
ViewHolder viewHolder; // view lookup cache stored in tag
final View result;
if (convertView == null) {
viewHolder = new ViewHolder();
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(R.layout.row_item, parent, false);
viewHolder.txtName = (TextView) convertView.findViewById(R.id.name);
viewHolder.txtType = (TextView) convertView.findViewById(R.id.type);
viewHolder.txtVersion = (TextView) convertView.findViewById(R.id.version_number);
viewHolder.info = (ImageView) convertView.findViewById(R.id.item_info);
result=convertView;
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
result=convertView;
}
Animation animation = AnimationUtils.loadAnimation(mContext, (position > lastPosition) ? R.anim.up_from_bottom : R.anim.down_from_top);
result.startAnimation(animation);
lastPosition = position;
viewHolder.txtName.setText(dataModel.getName());
viewHolder.txtType.setText(dataModel.getType());
viewHolder.txtVersion.setText(dataModel.getVersion_number());
viewHolder.info.setOnClickListener(this);
viewHolder.info.setTag(position);
// Retornar a visualização concluída para renderizar na tela
return convertView;
}
}
No código acima, adicionamos um onClickListener
ao ImageView que exibe um SnackBar quando clicado com uma descrição para a linha respectiva. Além disso, as linhas da lista são animadas ao serem roladas. Os dois arquivos de recursos XML de animação estão fornecidos abaixo. down_from_top.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="https://schemas.android.com/apk/res/android"
android:shareInterpolator="@android:anim/decelerate_interpolator">
<translate
android:fromXDelta="0%" android:toXDelta="0%"
android:fromYDelta="-100%" android:toYDelta="0%"
android:duration="400" />
</set>
up_from_bottom.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="https://schemas.android.com/apk/res/android"
android:shareInterpolator="@android:anim/decelerate_interpolator">
<translate
android:fromXDelta="0%" android:toXDelta="0%"
android:fromYDelta="100%" android:toYDelta="0%"
android:duration="400" />
</set>
O MainActivity.java
onde o CustomAdapter é definido para a ListView é definido abaixo. Junto com isso, um ArrayList aleatório de objetos DataModel é populado. MainActivity.java
public class MainActivity extends AppCompatActivity {
ArrayList dataModels;
ListView listView;
private static CustomAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
listView=(ListView)findViewById(R.id.list);
dataModels= new ArrayList<>();
dataModels.add(new DataModel("Apple Pie", "Android 1.0", "1","September 23, 2008"));
dataModels.add(new DataModel("Banana Bread", "Android 1.1", "2","February 9, 2009"));
dataModels.add(new DataModel("Cupcake", "Android 1.5", "3","April 27, 2009"));
dataModels.add(new DataModel("Donut","Android 1.6","4","September 15, 2009"));
dataModels.add(new DataModel("Eclair", "Android 2.0", "5","October 26, 2009"));
dataModels.add(new DataModel("Froyo", "Android 2.2", "8","May 20, 2010"));
dataModels.add(new DataModel("Gingerbread", "Android 2.3", "9","December 6, 2010"));
dataModels.add(new DataModel("Honeycomb","Android 3.0","11","February 22, 2011"));
dataModels.add(new DataModel("Ice Cream Sandwich", "Android 4.0", "14","October 18, 2011"));
dataModels.add(new DataModel("Jelly Bean", "Android 4.2", "16","July 9, 2012"));
dataModels.add(new DataModel("Kitkat", "Android 4.4", "19","October 31, 2013"));
dataModels.add(new DataModel("Lollipop","Android 5.0","21","November 12, 2014"));
dataModels.add(new DataModel("Marshmallow", "Android 6.0", "23","October 5, 2015"));
adapter= new CustomAdapter(dataModels,getApplicationContext());
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView > parent, View view, int position, long id) {
DataModel dataModel= dataModels.get(position);
Snackbar.make(view, dataModel.getName()+"\n"+dataModel.getType()+" API: "+dataModel.getVersion_number(), Snackbar.LENGTH_LONG)
.setAction("No action", null).show();
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflar o menu; isso adiciona itens à barra de ação se estiver presente.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Lidar com cliques nos itens da barra de ação aqui. A barra de ação irá
// manipular automaticamente cliques no botão Início/Para cima, desde
// que você especifique uma atividade pai no AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
A saída do aplicativo em ação é mostrada abaixo. Isso encerra este tutorial. Você pode baixar o projeto final Android ListView Custom Adapter a partir do link abaixo.
Baixar Projeto Adaptador Personalizado de ListView para Android
Referência: Guia da API ListView