Cómo crear listas dinámicas con RecyclerView Parte de Android Jetpack.
RecyclerView facilita que se muestren de manera eficiente grandes conjuntos de datos. Tú proporcionas los datos y defines el aspecto de cada elemento, y la biblioteca RecyclerView creará los elementos de forma dinámica cuando se los necesite.
Como su nombre lo indica, RecyclerView recicla esos elementos individuales. Cuando un elemento se desplaza fuera de la pantalla, RecyclerView no destruye su vista. En cambio, reutiliza la vista para los elementos nuevos que se desplazaron y ahora se muestran en pantalla. RecyclerView mejora el rendimiento y la capacidad de respuesta de tu app, y reduce el consumo de energía.
Clases clave
Varias clases trabajan juntas para compilar tu lista dinámica.
RecyclerView
es elViewGroup
que contiene las vistas correspondientes a tus datos. Es una vista en sí misma, por lo que agregasRecyclerView
a tu diseño de la misma manera en que agregarías cualquier otro elemento de la IU.Cada elemento individual de la lista está definido por un objeto contenedor de vistas. Cuando se lo crea, este contenedor no tiene datos asociados. Después de crearlo, la
RecyclerView
lo vincula a sus datos. Para definir el contenedor de vistas, debes extenderRecyclerView.ViewHolder
.El
RecyclerView
solicita vistas y las vincula a sus datos llamando a los métodos en el adaptador. Para definir el adaptador, extiendeRecyclerView.Adapter
.El administrador de diseño organiza los elementos individuales de tu lista. Puedes usar uno de los administradores de diseño proporcionados por la biblioteca RecyclerView o puedes definir el tuyo. Todos los administradores de diseño se basan en la clase abstracta
LayoutManager
de la biblioteca.
Puedes ver cómo se relacionan todas las piezas en la app de ejemplo de RecyclerView (Kotlin) o la app de ejemplo de RecyclerView (Java).
Pasos para implementar tu RecyclerView
Si vas a usar RecyclerView, debes realizar algunas acciones. Se explican en detalle en las siguientes secciones.
Decide cómo se verá la lista o cuadrícula. Por lo general, puedes usar uno de los administradores de diseño estándar de la biblioteca RecyclerView.
Diseña el aspecto y el comportamiento de cada elemento de la lista. En función de este diseño, extiende la clase
ViewHolder
. Tu versión deViewHolder
proporciona todas las funcionalidades para tus elementos de lista. El contenedor de vistas es un wrapper alrededor de unaView
, yRecyclerView
la administra.Define el
Adapter
que asocia tus datos con las vistas delViewHolder
.
También existen opciones de personalización avanzada que te permiten adaptar la RecyclerView a tus necesidades exactas.
Cómo planificar tu diseño
Los elementos de tu RecyclerView se organizan por una clase LayoutManager
. La biblioteca RecyclerView proporciona tres administradores de diseño, que controlan las situaciones de diseño más comunes:
LinearLayoutManager
dispone los elementos en una lista unidimensional.GridLayoutManager
organiza los elementos en una cuadrícula bidimensional:- Si la cuadrícula está organizada de forma vertical,
GridLayoutManager
intenta que todos los elementos de cada fila tengan el mismo ancho y la misma altura, pero las filas pueden tener alturas distintas. - Si la cuadrícula está organizada de forma horizontal,
GridLayoutManager
intenta que todos los elementos de cada columna tengan el mismo ancho y la misma altura, pero las columnas pueden tener anchos distintos.
- Si la cuadrícula está organizada de forma vertical,
StaggeredGridLayoutManager
es similar aGridLayoutManager
, pero no requiere que los elementos de una fila tengan la misma altura (en cuadrículas verticales) o que los elementos de la misma columna tengan el mismo ancho (en cuadrículas horizontales). El resultado es que los elementos de una fila o columna pueden terminar compensándose entre sí.
También debes diseñar el diseño de los elementos individuales. Lo necesitarás cuando diseñes el contenedor de vistas, como se describe en la siguiente sección.
Cómo implementar el adaptador y el contenedor de vistas
Una vez que determines el diseño, deberás implementar Adapter
y ViewHolder
. Estas dos clases trabajan juntas para definir la forma en que se muestran tus datos. El ViewHolder
es un wrapper alrededor de una View
que contiene el diseño de un elemento individual de la lista. El Adapter
crea objetos ViewHolder
según sea necesario y también establece los datos para esas vistas. El proceso de asociar vistas con sus datos se denomina vinculación.
Cuando defines tu adaptador, anulas tres métodos clave:
onCreateViewHolder()
:RecyclerView
Llama a este método siempre que necesita crear unaViewHolder
nueva. El método crea y, luego, inicializa laViewHolder
y suView
asociada, pero no completa el contenido de la vista; aún no se vinculó laViewHolder
con datos específicos.onBindViewHolder()
:RecyclerView
Llama a este método para asociar unaViewHolder
con los datos. El método recupera los datos correspondientes y los usa para completar el diseño del contenedor de vistas. Por ejemplo, siRecyclerView
muestra una lista de nombres, el método podría encontrar el nombre apropiado en la lista y completar el widgetTextView
del contenedor de vistas.getItemCount()
:RecyclerView
llama a este método para obtener el tamaño del conjunto de datos. Por ejemplo, en una app de libreta de direcciones, ese tamaño podría ser la cantidad total de direcciones. RecyclerView lo usa para determinar cuándo no hay más elementos que se puedan mostrar.
A continuación, se muestra un ejemplo típico de un adaptador simple con una ViewHolder
anidada que muestra una lista de datos. En este caso, RecyclerView muestra una lista simple de elementos de texto. Al adaptador se le pasa un array de cadenas que contiene el texto para los elementos ViewHolder
.
Kotlin
class CustomAdapter(private val dataSet: Array<String>) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() { /** * Provide a reference to the type of views that you are using * (custom ViewHolder) */ class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { val textView: TextView init { // Define click listener for the ViewHolder's View textView = view.findViewById(R.id.textView) } } // Create new views (invoked by the layout manager) override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder { // Create a new view, which defines the UI of the list item val view = LayoutInflater.from(viewGroup.context) .inflate(R.layout.text_row_item, viewGroup, false) return ViewHolder(view) } // Replace the contents of a view (invoked by the layout manager) override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) { // Get element from your dataset at this position and replace the // contents of the view with that element viewHolder.textView.text = dataSet[position] } // Return the size of your dataset (invoked by the layout manager) override fun getItemCount() = dataSet.size }
Java
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> { private String[] localDataSet; /** * Provide a reference to the type of views that you are using * (custom ViewHolder) */ public static class ViewHolder extends RecyclerView.ViewHolder { private final TextView textView; public ViewHolder(View view) { super(view); // Define click listener for the ViewHolder's View textView = (TextView) view.findViewById(R.id.textView); } public TextView getTextView() { return textView; } } /** * Initialize the dataset of the Adapter * * @param dataSet String[] containing the data to populate views to be used * by RecyclerView */ public CustomAdapter(String[] dataSet) { localDataSet = dataSet; } // Create new views (invoked by the layout manager) @Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { // Create a new view, which defines the UI of the list item View view = LayoutInflater.from(viewGroup.getContext()) .inflate(R.layout.text_row_item, viewGroup, false); return new ViewHolder(view); } // Replace the contents of a view (invoked by the layout manager) @Override public void onBindViewHolder(ViewHolder viewHolder, final int position) { // Get element from your dataset at this position and replace the // contents of the view with that element viewHolder.getTextView().setText(localDataSet[position]); } // Return the size of your dataset (invoked by the layout manager) @Override public int getItemCount() { return localDataSet.length; } }
El diseño de cada elemento de vista se define en un archivo de diseño XML, como de costumbre.
En este caso, la app tiene un archivo text_row_item.xml
como el siguiente:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/list_item_height"
android:layout_marginLeft="@dimen/margin_medium"
android:layout_marginRight="@dimen/margin_medium"
android:gravity="center_vertical">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/element_text"/>
</FrameLayout>
Próximos pasos
En el siguiente fragmento de código, se muestra cómo puedes usar el RecyclerView
.
Kotlin
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val dataset = arrayOf("January", "February", "March") val customAdapter = CustomAdapter(dataset) val recyclerView: RecyclerView = findViewById(R.id.recycler_view) recyclerView.layoutManager = LinearLayoutManager(this) recyclerView.adapter = customAdapter } }
Java
RecyclerView recyclerView = findViewById(R.id.recycler_view); recyclerView.layoutManager = new LinearLayoutManager(this) recyclerView.setAdapter(customAdapter);
La biblioteca también ofrece muchas formas de personalizar tu implementación. Para obtener más información, consulta Personalización avanzada de RecyclerView.
Recursos adicionales
Para obtener más información sobre las pruebas en Android, consulta los siguientes recursos.