Tutorial Para Crear Un RecyclerView Junto A CardViews En Android

¿Aún no sabes usar el RecyclerView en conjunto con CardViews?, ¿Quieres que tus aplicaciones proyecten las nuevas nociones del Material Design en su interfaz?, entonces este tutorial es para ti.

Verás cómo crear paso a paso una lista contenedora de tarjetas estilizadas, donde se proyectaran los atributos de elevación y bordes redondeados  para hacer una interfaz novedosa.

El objetivo de este tutorial es mostrarte la secuencia básica para crear una lista de tarjetas…

Descargar Proyecto Android Studio De “Kawaii Cards”

…para ello usaremos un ejemplo completo llamado KawaiiCards. Esta aplicación contiene 5 elementos dentro de una lista.

Cada ítem contiene información básica algunas series de Anime que ofrece un servicio web. Visualmente la tarjeta contiene una imagen de presentación, el nombre y la cantidad de vistas que ha tenido la serie.

Si sigues el tutorial hasta el final, tu aplicación podrá quedar con el siguiente aspecto:

Aplicación Android con Material Design usando RecyclerView y CardView

Para desbloquear el link de descarga del código completo, haz lo siguiente:

Crear listas con el RecyclerView

Un RecyclerView es un contenedor de elementos en forma de lista al igual que la clase ListView. Aunque ambos tienen la misma función, este nuevo elemento permite “reciclar” los ítems que ya no son visibles por el usuario debido al scrolling. Por lo que es ideal para proyectos que manejan grandes volúmenes de ítems que se actualizan constantemente, limitando la visibilidad de elementos.

Lee también Listas y Adaptadores en Android

Adicionalmente permite configurar una serie de animaciones para la eliminación, desplazamiento y creación de nuevos elementos en tiempo real.

La creación y administración de un RecyclerView es similar a la de un ListView. Se necesita una fuente de datos que provea la información lógica de cada elemento y un adaptador que los lea, interprete e infle. Pero también es necesario un nuevo elemento llamado LayoutManager.

El LayoutManager es el encargado de añadir y reusar los views en el recycler. Su función es calcular las posiciones fuera del foco del usuario y así reemplazar el contenido de un ítem fuera del volumen visual por el contenido de otro. Esto reduce los tiempos de ejecución, ya que el número de infladas es menor.

Crear un nuevo proyecto en Android Studio

Lo primero que harás será crear un nuevo proyecto en Android Studio que contenga una sola actividad en blanco. Ponle como título KawaiiCards.

Añadir dependencia para el RecyclerView

Para usar el RecyclerView en tus proyectos Android Studio es necesario añadir la siguiente dependencia al sistema de construcción Gradle. Esto es debido a que este widget hace parte de la librería soporte v7 para manejar la compatibilidad:

dependencies {
    ...
    compile 'com.android.support:recyclerview-v7:21.0.+'
}

Crear el diseño de la actividad principal

Lo siguiente es ubicar como nodo principal un elemento del tipo <android.support.v7.widget.RecyclerView> para enfocar la acción de nuestra actividad principal en el recycler.

<android.support.v7.widget.RecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/reciclador"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="3dp"
    android:scrollbars="vertical" />

Recuerda que para ocupar el espacio completo de la pantalla dispositivo debemos usar match_parent en los atributos de dimensión.

Implementar fuente de datos

Recuerda que una fuente de datos es una colección de información bien sea declarada en estructuras simples de datos o una base de datos.

En este caso usaremos una lista de objetos del tipo Anime. Esta clase contiene tres atributos simples de los cuales hablamos en el inicio de este artículo: imagen, nombre y visitas. La idea es que estos objetos sirvan de alimento para el adaptador que se creará más adelante:

public class Anime {
    private int imagen;
    private String nombre;
    private int visitas;

    public Anime(int imagen, String nombre, int visitas) {
        this.imagen = imagen;
        this.nombre = nombre;
        this.visitas = visitas;
    }

    public String getNombre() {
        return nombre;
    }

    public int getVisitas() {
        return visitas;
    }

    public int getImagen() {
        return imagen;
    }
}

El atributo imagen guarda la identificación de una imagen que almacenaremos en los recursos drawables para realizar una referencia directa. Las imagenes han sido descargadas desde el portal mcanime.net, así que el credito es todo para ellos.

Crear adaptador para el RecyclerView

A continuación se creará el adaptador para el recycler a través de la clase RecyclerView.Adapter. Los adaptadores para recyclers deben contener una clase interna que extienda de RecyclerView.ViewHolder.

Un ViewHolder es un objeto que representa un ítem de la lista, el cual almacena las referencias de los views dentro del layout con propósitos de acceso rápido. Este objeto es la comunicación directa entre el LayoutManager y el adaptador, actuando como caché.

public class AnimeAdapter extends RecyclerView.Adapter<AnimeAdapter.AnimeViewHolder> {
    private List<Anime> items;

    public static class AnimeViewHolder extends RecyclerView.ViewHolder {
        // Campos respectivos de un item
        public ImageView imagen;
        public TextView nombre;
        public TextView visitas;

        public AnimeViewHolder(View v) {
            super(v);
            imagen = (ImageView) v.findViewById(R.id.imagen);
            nombre = (TextView) v.findViewById(R.id.nombre);
            visitas = (TextView) v.findViewById(R.id.visitas);
        }
    }

    public AnimeAdapter(List<Anime> items) {
        this.items = items;
    }

    @Override
    public int getItemCount() {
        return items.size();
    }

    @Override
    public AnimeViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View v = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.anime_card, viewGroup, false);
        return new AnimeViewHolder(v);
    }

    @Override
    public void onBindViewHolder(AnimeViewHolder viewHolder, int i) {
        viewHolder.imagen.setImageResource(items.get(i).getImagen());
        viewHolder.nombre.setText(items.get(i).getNombre());
        viewHolder.visitas.setText("Visitas:"+String.valueOf(items.get(i).getVisitas()));
    }
}

La clase AnimeAdapter extiende de RecyclerView.Adapter<AnimeAdapter.AnimeViewHolder>, lo que significa que será un adaptador que referencia sus ítems con objetos del tipo AnimeViewHolder. Con esta declaración el LayoutManager ya sabrá a qué tipo acudir para reducir el acceso por referencias.

Supongo que ya deduces la utilidad del método onCreateViewHolder(), el cual infla el contenido de un nuevo ítem para la lista. El método onBindViewHolder() es el que realiza las modificaciones del contenido de cada ítem. Por esta razón recibe como parámetros el view holder y la posición que ocupa en la fuente de datos.

No olvides sobrescribir getItemCount(), recuerda que este método es vital para que los adaptadores sepan la cantidad de elementos que se procesarán.

Diseñar el contenido de los CardViews

Un CardView es un contenedor capaz de presentar su aspecto con sombras y bordes redondeados. Para controlar el nivel de sombras se usa el atributo card_view:cardElevation y para los bordes el atributo card_view:cardCornerRadius.

Cards Material Design

Añadir dependencias para el CardView

Al igual que el RecyclerView, el CardView requiere que se incorpore una dependencia de compatabilidad al archivo build.gradle del proyecto Android Studio. Veamos:

dependencies {
    ...
    compile 'com.android.support:cardview-v7:21.0.+'
}

Crear layout para el CardView

Usa el elemento android.support.v7.widget.CardView para insertar tarjetas en tus layouts. Pero debido a que este elemento hereda de la clase FrameLayout, la forma en que deseamos acomodar los elementos no es posible dada su rigidez. Por esa razón añadiremos un RelativeLayout dentro de la tarjeta para obtener una mejor experiencia de usuario:

<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="150dp"
    card_view:cardCornerRadius="4dp"
    card_view:cardElevation="4dp"
    card_view:cardUseCompatPadding="true">

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">

        <ImageView
            android:id="@+id/imagen"
            android:layout_width="100dp"
            android:layout_height="150dp"
            android:scaleType="centerCrop" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:text="Large Text"
            android:id="@+id/nombre"
            android:layout_toRightOf="@+id/imagen"
            android:layout_alignParentTop="true"
            android:layout_marginLeft="10dp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:text="Small Text"
            android:id="@+id/visitas"
            android:layout_below="@+id/nombre"
            android:layout_alignLeft="@+id/nombre" />
        <View
            android:layout_width="wrap_content"
            android:layout_height="1dp"
            android:background="#ffd5d5d5"
            android:id="@+id/linea"
            android:layout_above="@+id/compartir"
            android:layout_toRightOf="@+id/imagen">

        </View>

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/compartir"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:src="@android:drawable/ic_menu_share"
            android:background="@color/material_blue_grey_800" />

    </RelativeLayout>
</android.support.v7.widget.CardView>

Como ves el elemento CardView es la raíz del archivo XML que representa el diseño de los ítems de la lista. Para redondear un poco los bordes se usó el valor de 4dp en cardCornerRadius. A su vez se declaró 4dp para la elevación y proyección de sombras de la tarjeta con cardElevation. El atributo cardUseCompatPadding define si el cardview tendrá un padding interno que lo diferencie de otros views.

En el caso de la imagen de presentación se decidió predeterminar sus dimensiones a un tamaño de 100dp x 150dp para implementar un formato visual sobrio. Adicionalmente se añadió un icono no funcional para compartir la visualización de la serie y una línea separadora entre el contenido y el footer de la tarjeta.

Lee también Configurar Layouts y Views en Android Studio

Relacionar RecyclerView con las CardViews

El último paso para poner en marcha la aplicación KawaiiCards es relacionar ambos views para conectar los datos a la vista. Ve a tu actividad principal y declara instancias globales para crear el RecyclerView, el LayoutManager y un nuevo adaptador.

/*
Declarar instancias globales
*/
private RecyclerView recycler;
private RecyclerView.Adapter adapter;
private RecyclerView.LayoutManager lManager;

Lo siguiente es obtener la instancia del RecyclerView, crear el layout manager, generar un lista con los ítems de ejemplo y finalmente crear el adaptador que coordine los elementos.

// Inicializar Animes
List items = new ArrayList();

items.add(new Anime(R.drawable.angel, "Angel Beats", 230));
items.add(new Anime(R.drawable.death, "Death Note", 456));
items.add(new Anime(R.drawable.fate, "Fate Stay Night", 342));
items.add(new Anime(R.drawable.nhk, "Welcome to the NHK", 645));
items.add(new Anime(R.drawable.suzumiya, "Suzumiya Haruhi", 459));

// Obtener el Recycler
recycler = (RecyclerView) findViewById(R.id.reciclador);
recycler.setHasFixedSize(true);

// Usar un administrador para LinearLayout
lManager = new LinearLayoutManager(this);
recycler.setLayoutManager(lManager);

// Crear un nuevo adaptador
adapter = new AnimeAdapter(items);
recycler.setAdapter(adapter);

Cuando se obtiene la instancia del recycler se usa el método setHasFixedSize() para optimizar las operaciones con los ítems. Con esta característica le estamos diciendo al recycler que el adaptador no variará su tamaño en toda la ejecución del programa.

El layout manager fue instanciado con la subclase LinearLayoutManager indicando que el recycler tomará la forma de lista vertical similar al ListView. Luego se relaciona al recycler con el método setLayoutManager().

También es posible usar el manager GridLayoutManager para mostrar los ítems en forma de grilla automatizada.
En la creación del nuevo adaptador se incluye la referencia de la lista que contiene las características de 5 series de anime. Estas son relacionadas al recycler con el método setAdapter().

Finalmente ejecuta la aplicación y tendrás el resultado mostrado en el inicio del artículo.