Un vistazo rápido al nuevo RecyclerView
Con la versión preview de android L, Google ha presentado dos nuevos Widgets, RecyclerView y CardView, este artículo tratará el primero, el RecyclerView.
Este nuevo Widget entra en juego cuando el propósito es mostrar gran número de Views repetidamente, listas, grids, etc..., tantas que no entran en la pantalla.
RecyclerView implementa un sistema para llevar a cabo esta tarea, de forma sencilla y eficiente.
Proyecto de ejemplo
Todos los ejemplos de código que se muestran en este artículo se pueden encontrar en este proyecto en GitHub de forma funcional:
https://github.com/saulmm/RecyclerView-demo.git
La API de RecyclerView
A diferencia del ListView, GridView, etc... el RecyclerView se dedica únicamente a lo que su nombre indica, reciclar, reutilizar recursos y evitar el uso reiterado del costoso findViewById, no se preocupa del aspecto visual, para ello está el LayoutManager.
Una clase una tarea, esa es la filosofía que sigue la API del RecyclerView, un paquete de clases internas cada una con una responsabilidad:
- Adapter
- ViewHolder
- LayoutManager
- ItemDecoration
- ItemAnimator Adapter
Esta clase se encarga de crear las Views necesarias para cada elemento del RecyclerView, además, está muy unida al ViewHolder, teniendo que ser indicado en la declaración de la clase, muchos pensaréis que esto no es nuevo, que Google ya aconsejara este patrón tiempo atrás, esta vez fuerza a utilizarlo, teniendo que ser indicado en la implementación del Adapter, un paso adelante, sin duda.
El método OnCreateViewHolder inicializa el ViewHolder
@Override public ViewHolder onCreateViewHolder(ViewGroup parentViewGroup, int i) {View rowView = LayoutInflater.from (parentViewGroup.getContext()) .inflate(R.layout.list_basic_item, parentViewGroup, false); return new ViewHolder (rowView); }</pre>
El método onBindViewHolder(ViewHolder viewholder, int position) se usa para configurar el contenido de las Views
@Override public void onBindViewHolder(ViewHolder viewHolder, int position) {final SampleModel rowData = sampleData.get(position); viewHolder.textViewSample.setText(rowData.getSampleText()); viewHolder.itemView.setTag(rowData); }</pre>
ViewHolder
Como venía diciendo, el patrón ViewHolder no es nada nuevo, de hecho Google, lo lleva recomendando desde hace tiempo, se puede pensar en el como un cache de las vistas, pudiendo reutilizarlas en vez de crearlas nuevamente.
@Override public static class ViewHolder extends RecyclerView.ViewHolder {private final TextView textViewSample; public ViewHolder(View itemView) { super(itemView); textViewSample = (TextView) itemView.findViewById( R.id.textViewSample); } }</pre>
LayoutManager
El LayoutManager se encarga del layout de todas las vistas dentro del RecyclerView, concretando con el LinearLayoutManager, permite entre otros acceder a elementos mostrados en la pantalla como el primer elemento, último, o por ejemplo, el último completamente visible, esto de forma horizontal o vertical, en el ejemplo se ha utilizado la disposición en vertical.
LinearLayoutManager mLayoutManager = new LinearLayoutManager(this); recyclerView.setLayoutManager(mLayoutManager);</pre>
ItemDecorator
Otro eslabón importante, son los llamados ItemDecorator, estos permiten modificar los elementos del RecycleView, este además, ofrece además ofrece un elemento llamado insets (márgenes) que pueden aplicarse a las vistas sin necesidad de modificar los parámetros del layout.
En el ejemplo, se muestra como se usan los ItemDecorators para dibujar un pequeño Divider entre los elementos del RecyclerView:
package saulmm.com.recyclerviewproject;ItemAnimatorimport android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.support.v7.widget.RecyclerView; import android.view.View;
public class SampleDivider extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = { android.R.attr.listDivider }; private Drawable mDivider; public SampleDivider(Context context) { TypedArray a = context.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(0); a.recycle(); } @Override public void onDrawOver(Canvas c, RecyclerView parent) { int left = parent.getPaddingLeft(); int right = parent.getWidth() - parent.getPaddingRight(); int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { View child = parent.getChildAt(i); RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); int top = child.getBottom() + params.bottomMargin; int bottom = top + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } }
}
La clase ItemAnimator como su nombre indica, anima el RecyclerView cuando se añade y se elimina un elemento, el RecyclerView utiliza un ItemAnimator por defecto.
El RecyclerView ha de saber cuando se inserta un elemento o se elimina, con elementos como ListViews, GridViews, etc... esto se conseguía llamando al método notifyDataSetChanged(), a nivel de performance, es bastante costoso, ya que redibuja todos los items en el layout, lo propio con el RecyclerView es usar el método notifyItemInserted() para añadir, y notifyItemRemoved() para eliminar, actualizando solo la parte apropiada.
Referencias:
Wolfram RittMeyer - A first Glance at Android's RecyclerView