🚀 3.6 ListViews

Para exibir coleções de dados, como a lista de viagens ou gastos, o Android utiliza componentes de listagem. O ListView é o precursor clássico e, embora o RecyclerView seja o padrão atual de mercado, entender o ListView é essencial para compreender a evolução das listas no Android.

IMPORTANT

O Sucessor: RecyclerView Para aplicações de escala profissional, utilize sempre o RecyclerView. Ele é mais eficiente em termos de memória (reaproveita views de forma inteligente) e oferece animações nativas e maior flexibilidade de layout.

Implementando a Lista de Viagens (ViewBinding & Java 17)

Em vez de utilizarmos a antiga ListActivity, utilizaremos uma AppCompatActivity padrão com um ListView em seu layout XML. Isso nos dá total controle sobre a interface.

Layout XML (activity_viagem_list.xml)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
 
    <ListView
        android:id="@+id/listViewViagens"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

Atividade de Listagem

Utilizamos o SimpleAdapter para mapear os dados para o layout customizado lista_viagem.xml:

public class ViagemListActivity extends AppCompatActivity {
 
    private ActivityViagemListBinding binding;
 
    @Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityViagemListBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
 
        var de = new String[] { "imagem", "destino", "data", "total" };
        var para = new int[] { R.id.tipoViagem, R.id.destino, R.id.data, R.id.valor };
 
        var adapter = new SimpleAdapter(this, listarViagens(), R.layout.lista_viagem, de, para);
        binding.listViewViagens.setAdapter(adapter);
 
        binding.listViewViagens.setOnItemClickListener((parent, view, position, id) -> {
            var intent = new Intent(this, GastoListActivity.class);
            startActivity(intent);
        });
    }
 
    private List<Map<String, Object>> listarViagens() {
        var viagens = new ArrayList<Map<String, Object>>();
 
        viagens.add(Map.of(
            "imagem", R.drawable.negocios,
            "destino", "São Paulo",
            "data", "02/02/2024 a 04/02/2024",
            "total", "Gasto total R$ 314,98"
        ));
 
        viagens.add(Map.of(
            "imagem", R.drawable.lazer,
            "destino", "Maceió",
            "data", "14/05/2024 a 22/05/2024",
            "total", "Gasto total R$ 2.534,67"
        ));
 
        return viagens;
    }
}

Customização Avançada com ViewBinder

Para a lista de gastos, queremos mudar a cor de fundo dinamicamente. Para isso, utilizamos um ViewBinder. Note o uso de ContextCompat para garantir a compatibilidade de cores:

private class GastoViewBinder implements SimpleAdapter.ViewBinder {
    @Override
public boolean setViewValue(View view, Object data, String textRepresentation) {
        if (view.getId() == R.id.categoria) {
            var colorId = (Integer) data;
            // Forma correta de obter cores no Android moderno
            view.setBackgroundColor(ContextCompat.getColor(view.getContext(), colorId));
            return true;
        }
        return false;
    }
}

TIP

Ao lidar com listas longas, o uso de Map.of() ou List.of() (Java 9+) torna a inicialização de dados estáticos muito mais legível e concisa.

CAUTION

Ao migrar para o RecyclerView no futuro, você substituirá o SimpleAdapter por uma classe herdeira de RecyclerView.Adapter, que implementa o padrão ViewHolder de forma nativa e obrigatória.


⬅️ Capítulo Anterior | Próximo Capítulo ➡️