Los elementos dentro de un RecyclerView de Android son del mismo tipo y tienen la misma apariencia; pero en ocasiones vamos a necesitar mostrar distintos elementos o vistas dentro del mismo RecyclerView.
Por ejemplo, en una lista de elementos tal vez solo mostramos algunos, y al final una opción de “Ver más” o “Ver todos”.
Para lograr esto solo tenemos que modificar el adaptador
Vamos a ver cómo insertar distintos elementos en un RecyclerView.
Podemos insertarlos al inicio, al final o en cualquier forma, es decir, podemos definir la manera de inserción a través de una función.
Comenzamos definiendo los ViewHolders, pues vamos a usar uno u otro en la lista:
class ViewHolderGasto extends RecyclerView.ViewHolder {
TextView descripcion, monto, categoria, fecha;
ViewHolderGasto(View itemView) {
super(itemView);
this.descripcion = itemView.findViewById(R.id.tvDescripcionGasto);
this.monto = itemView.findViewById(R.id.tvMontoGasto);
this.categoria = itemView.findViewById(R.id.tvCategoriaGasto);
this.fecha = itemView.findViewById(R.id.tvFechaGasto);
}
}
class ViewHolderVerMas extends RecyclerView.ViewHolder {
TextView textoVerMas;
ViewHolderVerMas(View itemView) {
super(itemView);
this.textoVerMas = itemView.findViewById(R.id.tvVerMas);
}
}
Tengo dos ViewHolders, el contenido de los mismos no importa, solo que uno va a mostrar la descripción de un gasto y el otro va a mostrar un elemento que diga “Ver más”
Ahora vamos a definir la función que se encarga de decir cuál vista vamos a mostrar.
Tenemos que regresar un entero, recibimos la posición del elemento de la lista. Yo solo regreso un valor u otro, pero en la práctica puede definirse cualquier rango de valores.
@Override
public int getItemViewType(int position) {
if (position == listaDeGastos.size() - 1) return TIPO_VER_MAS;
return TIPO_NORMAL;
}
Lo que hago es que si el elemento es el último (ya que position
es la longitud de mi lista menos uno) regreso una constante llamada TIPO_VER_MAS
, y si no, TIPO_NORMAL
.
Las constantes son solo constantes, las puse para no escribir números sin nombre.
De esta manera, al final de la lista se mostrará un elemento que dirá “Ver todos los gastos”
Ya definimos el método que va a indicar cuál vista usar, y también definimos ambos ViewHolders.
Ahora vamos a definir la función que crea el ViewHolder dependiendo del tipo.
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
switch (viewType) {
case TIPO_VER_MAS:
View filaVerMas = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.fila_ver_mas, viewGroup, false);
return new ViewHolderVerMas(filaVerMas);
case TIPO_NORMAL:
default:
View filaGasto = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.fila_gasto, viewGroup, false);
return new ViewHolderGasto(filaGasto);
}
}
Si el tipo es TIPO_VER_MAS
entonces regresamos el layout de fila_ver_mas
, con el ViewHolder de ver más.
Si no (y por defecto) regresamos la fila que mostrará los detalles del gasto, en el ViewHolder de ViewHolderGasto
.
Ahora veamos la última parte que se encarga de poner los datos a la vista que va dentro del RecyclerView:
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int i) {
switch (holder.getItemViewType()) {
case TIPO_NORMAL:
ViewHolderGasto viewHolderGasto = (ViewHolderGasto) holder;
Gasto gasto = listaDeGastos.get(i);
viewHolderGasto.descripcion.setText(gasto.getDescripcion());
viewHolderGasto.monto.setText(gasto.getMontoAsString());
viewHolderGasto.categoria.setText(gasto.getCategoria().getNombre());
viewHolderGasto.fecha.setText(gasto.getFechaFormateada());
break;
case TIPO_VER_MAS:
default:
ViewHolderVerMas viewHolderVerMas = (ViewHolderVerMas) holder;
viewHolderVerMas.textoVerMas.getContext().getString(R.string.ver_todos_gastos);
viewHolderVerMas.textoVerMas.setText(viewHolderVerMas.textoVerMas.getContext().getString(R.string.ver_todos_gastos));
break;
}
}
Aquí es en donde dibujamos los elementos, tenemos acceso completo a la vista o mejor dicho, al layout.
El código completo del adaptador (junto con las constantes para los tipos) queda como se ve a continuación:
package me.parzibyte.administrate;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
import me.parzibyte.administrate.entidades.Gasto;
public class AdaptadorGastos extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Gasto> listaDeGastos;
private final int TIPO_NORMAL = 1;
private final int TIPO_VER_MAS = 0;
public void setListaDeGastos(List<Gasto> listaDeGastos) {
this.listaDeGastos = listaDeGastos;
}
public AdaptadorGastos(List<Gasto> gastos) {
this.listaDeGastos = gastos;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
switch (viewType) {
case TIPO_VER_MAS:
View filaVerMas = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.fila_ver_mas, viewGroup, false);
return new ViewHolderVerMas(filaVerMas);
case TIPO_NORMAL:
default:
View filaGasto = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.fila_gasto, viewGroup, false);
return new ViewHolderGasto(filaGasto);
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int i) {
switch (holder.getItemViewType()) {
case TIPO_NORMAL:
ViewHolderGasto viewHolderGasto = (ViewHolderGasto) holder;
Gasto gasto = listaDeGastos.get(i);
viewHolderGasto.descripcion.setText(gasto.getDescripcion());
viewHolderGasto.monto.setText(gasto.getMontoAsString());
viewHolderGasto.categoria.setText(gasto.getCategoria().getNombre());
viewHolderGasto.fecha.setText(gasto.getFechaFormateada());
break;
case TIPO_VER_MAS:
default:
ViewHolderVerMas viewHolderVerMas = (ViewHolderVerMas) holder;
viewHolderVerMas.textoVerMas.getContext().getString(R.string.ver_todos_gastos);
viewHolderVerMas.textoVerMas.setText(viewHolderVerMas.textoVerMas.getContext().getString(R.string.ver_todos_gastos));
break;
}
}
@Override
public int getItemCount() {
return listaDeGastos.size();
}
@Override
public int getItemViewType(int position) {
if (position == listaDeGastos.size() - 1) return TIPO_VER_MAS;
return TIPO_NORMAL;
}
class ViewHolderGasto extends RecyclerView.ViewHolder {
TextView descripcion, monto, categoria, fecha;
ViewHolderGasto(View itemView) {
super(itemView);
this.descripcion = itemView.findViewById(R.id.tvDescripcionGasto);
this.monto = itemView.findViewById(R.id.tvMontoGasto);
this.categoria = itemView.findViewById(R.id.tvCategoriaGasto);
this.fecha = itemView.findViewById(R.id.tvFechaGasto);
}
}
class ViewHolderVerMas extends RecyclerView.ViewHolder {
TextView textoVerMas;
ViewHolderVerMas(View itemView) {
super(itemView);
this.textoVerMas = itemView.findViewById(R.id.tvVerMas);
}
}
}
El listener es otro tema, pero si quieres un consejo, simplemente agrega un elemento nulo o con valores por defecto a la lista; al renderizarse no se mostrará, pues tomará la otra vista.
En mi caso hice lo siguiente:
gastos.add(new Gasto(-1, new Categoria(-1, ""), "", new BigDecimal("0"), null));
Y en el listener:
public void onClick(View view, int position) {
Gasto gasto = gastos.get(position);
if (gasto.getId() < 0) {
Toast.makeText(getContext(), "Ver más", Toast.LENGTH_SHORT).show();
return;
}
//Aquí lo que se hace si es un elemento normal
}
Aunque ahora que lo pienso, no debería fijarme en el gasto, sino en position
.
Después de todo eso que acabo de mostrar, pude lograr lo siguiente:
Así podemos mostrar dos, tres o miles de vistas distintas. Y como lo dije, pueden ser mostradas en cualquier posición.
Hoy te voy a presentar un creador de credenciales que acabo de programar y que…
Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…
En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…
En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…
Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…
En este artículo te voy a enseñar cómo usar un "top level await" esperando a…
Esta web usa cookies.
Ver comentarios
friend I have two different queries to a DB, one loads the courses table in recyclerview, but the user can save favorite courses and they are added to another table in the DB: How would I show the favorites in a different obvious layout inside recyclerview? I have duplicated the adapter class and made everything, and only the courses are shown, please give me a page or advice how can I do it? sorry my english I use translator