Ejemplo de SwipeRefreshLayout mas RecyclerView en Android

Ejemplo de un SwipeRefreshLayout en una Aplicación Android
¿Quieres cargar más elementos en tu lista usando un indicador de actividad circular que muestran muchas otras aplicaciones Android? Entonces este tutorial es para ti, ya que te enseñará a usar el patrón de diseño "Swipe to Refresh", el cual refresca el contenido de una view con tan solo arrastrar verticalmente la interfaz.

Para comprender este tema crearemos una pequeña aplicación llamada Revista Tempor. Esta aplicación se basa en una lista que contiene artículos que permiten votar opciones dentro de listas propuestas por los usuarios. Veamos un poco su funcionamiento:

Asegúrate de tener claros los siguientes temas para comenzar con pie derecho el tutorial:

Crear listas con un RecyclerView

Uso de Tareas Asíncronas en AndroidCONTENIDO

Crear Proyecto en Android Studio

Diseñar Actividad Principal de la Aplicación

Diseñar ítems para el RecyclerView

Crear una fuente de datos para poblar la lista

Crear un Adaptador para la lista

Implementar la clase SwipeRefreshLayout

Implementar la escucha OnRefreshListener

Cambiar color de la animación de progreso

1. Crear un nuevo proyecto en Android Studio

El primer paso es crear un nuevo proyecto con una actividad en blanco. Esta acción se lleva a cabo yendo al menú File y luego seleccionando la opción New Project...

2. Diseñar Actividad Principal de la Aplicación

Debido a que la actividad principal está basada en una lista, es posible utilizar el elemento <android.support.v7.widget.RecyclerView> como nodo raíz. Con ello se tendríamos un layout como el siguiente:

<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" />

3. Diseñar ítems para el RecyclerView

El siguiente paso es crear el layout para los ítems de la lista. Como se vio en el gif de la parte inicial, cada ítem se compone del título de la lista, la cantidad de votos que lleva hasta el momento y una imagen lateral que hace alusión al contenido del ítem. Este diseño lo hemos realizado un sin número de veces por lo que no requiere explicación.

Veamos:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:padding="10dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/imagen"
android:src="@drawable/portafolio"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="false"
android:layout_centerVertical="true"
android:layout_marginRight="10dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Medium Text"
android:id="@+id/titulo"
android:layout_toRightOf="@+id/imagen"
android:layout_marginBottom="3dp"
android:layout_alignParentTop="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Small Text"
android:id="@+id/votos"
android:textColor="#ff7e7e7e"
android:layout_alignLeft="@+id/titulo"
android:layout_alignParentBottom="true" />
</RelativeLayout>

4. Crear una fuente de fatos para poblar la lista

Hasta ahora ya sabemos que los ítems de la lista tienen una estructura definida. Estos poseen tres atributos fundamentales para ser representados lógicamente en una clase. Así que definiremos una nueva entidad llamada Lista, la cual tiene el siguiente esquema:

public class Lista {
private String titulo;
private String votos;
private int idImagen;
public Lista(String titulo, String votos, int idImagen) {
this.titulo = titulo;
this.votos = votos;
this.idImagen = idImagen;
}
public String getTitulo() {
return titulo;
}
public void setTitulo(String titulo) {
this.titulo = titulo;
}
public String getVotos() {
return votos;
}
public void setVotos(String votos) {
this.votos = votos;
}
public int getIdImagen() {
return idImagen;
}
public void setIdImagen(int idImagen) {
this.idImagen = idImagen;
}
}

Si nos detenemos a pensar por un instante en la lógica de la carga regular de nuevos ítems, surgirá la siguiente pregunta: ¿De dónde se obtendrán una gran variedad de elementos, si no vamos a conectarnos en tiempo real a un servidor externo? La respuesta está en la duplicación aleatoria.

Así es, crearemos un array de elementos de tipo Lista donde guardaremos una cantidad fija de elementos con sus respectivas características. Luego se creará un método que retorne en una lista que contenga ítems seleccionados al azar. Esto permitirá mostrar variación a la hora de refrescar los ítems. Con esta forma de trabajo al menos nuestro ejemplo no quedará extremadamente estático.

La traducción de todo lo dicho es la creación de la clase ConjuntoLista, la cual contiene el arreglo de elementos predeterminados y el método de distribución aleatoria:

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Random;
*
* Creado por Hermosa Programación

public class ConjuntoListas {
static final Lista LISTAS[] = {
new Lista("Lista de las 10 mejores herramientas de analiticas", "3022", R.drawable.analytics),
new Lista("Lista de los mejores servicios de entrega en Cali", "1234", R.drawable.box),
new Lista("Lista de los navegadores mas rápidos", "2452", R.drawable.browser),
new Lista("Lista de las aplicaciones mas populares de chat", "4532", R.drawable.bubbles),
new Lista("Lista de los hábitos que te hacen perder tiempo", "24321", R.drawable.clock),
new Lista("Lista de las joyas mas deseadas por las mujeres", "9090", R.drawable.diamond),
new Lista("Lista de los países mas ricos del mundo", "256", R.drawable.graph),
new Lista("Lista de las computadoras MAC mas caras", "2453", R.drawable.imac),
new Lista("Lista de los videojuegos mas jugados", "1112", R.drawable.joypad),
new Lista("Lista de los mejores DJs de Europa", "4512", R.drawable.keyboards),
new Lista("Lista de los actores mas guapos de Bollywood", "123", R.drawable.man),
new Lista("Lista de los los lugares turisticos mas hermosos", "4452", R.drawable.map),
new Lista("Lista de los servicios en la nube con mayor espacio gratis", "2222", R.drawable.open_box),
new Lista("Lista de los peores regalos que puedas dar", "3849", R.drawable.pack),
new Lista("Lista de 20 oportunidades de negocio para jovenes", "456", R.drawable.portafolio),
new Lista("Lista de las 10 herramientas de edición musical mas usadas", "7840", R.drawable.settings),
new Lista("Lista de los conciertos mas esperados de octubre", "9808", R.drawable.speakers),
new Lista("Lista de objetivos mas comunes de un Desarrollador Android", "1234", R.drawable.target),
new Lista("Lista de los 5 peores licores de China", "5556", R.drawable.wine),
new Lista("Lista de las 10 mujeres mas deseadas del equipo Google", "567", R.drawable.woman)
};
*
* Este método retorna en una lista aleatoria basada en el
* atributo LISTAS.
*
* El parámetro entero count es el tamaño deseado de la lista
* resultante

public static ArrayList randomList(int count) {
Random random = new Random();
HashSet items = new HashSet();
// Restricción de tamaño
count = Math.min(count, LISTAS.length);
while (items.size() < count) {
items.add(LISTAS[random.nextInt(LISTAS.length)]);
}
return new ArrayList(items);
}
}

Como ves, me he tomado el trabajo de crear 20 elementos distintos para generar variedad. Adicionalmente encontramos el método randomList(), donde se rellena un conjunto de datos hash que apuntan a un índice aleatorio del arreglo LISTAS.

5. Crear un Adaptador para la lista

Teniendo en cuenta que la fuente de datos contiene solo tres atributos, entonces debemos proceder a inflar los views de cada ítem en una instancia RecyclerView.Adapter.

package com.herprogramacion.revistatempor;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
*
* Creado por Hermosa Programación

public class ListaAdapter extends RecyclerView.Adapter {
private List items;
public static class AnimeViewHolder extends RecyclerView.ViewHolder {
// Campos de la lista
public ImageView imagen;
public TextView titulo;
public TextView votos;
public AnimeViewHolder(View v) {
super(v);
imagen = (ImageView) v.findViewById(R.id.imagen);
titulo = (TextView) v.findViewById(R.id.titulo);
votos = (TextView) v.findViewById(R.id.votos);
}
}
public ListaAdapter(List items) {
this.items = items;
}

Añade una lista completa de items

public void addAll(List lista){
items.addAll(lista);
notifyDataSetChanged();
}

Permite limpiar todos los elementos del recycler

public void clear(){
items.clear();
notifyDataSetChanged();
}

@Override
public int getItemCount() {
return items.size();
}
@Override
public AnimeViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.lista, viewGroup, false);
return new AnimeViewHolder(v);
}
@Override
public void onBindViewHolder(AnimeViewHolder viewHolder, int i) {
viewHolder.imagen.setImageResource(items.get(i).getIdImagen());
viewHolder.titulo.setText(items.get(i).getTitulo());
viewHolder.votos.setText("Votos:"+String.valueOf(items.get(i).getVotos()));
}
}

Es necesario destacar que tenemos dos nuevos métodos que no se habían implementado antes. Se trata de addAll() y clear(). El primero permite que añadamos un conjunto de elementos directamente hacia la fuente alimentadora de datos del adaptador, que en este caso es el atributo items.

Tanto addAll() como clear() usan el método notifyDataSetChanged(), el cual notifica al adaptador que la fuente de datos ha cambiado y que por ende es necesario refrescar la lista. Con esas implementaciones ya estamos listos para remover y añadir elementos al momento de realizar un Swipe para la recarga.

6. Implementar la clase SwipeRefreshLayout

La clase android.support.v4.widget.SwipeRefreshLayout es el motivo del porqué estás leyendo este artículo, ya que es la que permite implementar el refresco del contenido de un ítem a través de un gesto de arrastre vertical. La metódica consiste en envolver al view que deseamos refrescar (en este caso el recycler) dentro de un elemento SwipeRefreshLayout.

Cabe aclarar que este elemento solo puede contener un view en su jerarquía, porque se concentra en la superficie de un único elemento. Por eso debes usar match_parent para que el elemento hijo sea abarcado por completo y el indicador circular se presente efectivamente.

Esta situación modifica el panorama que teníamos hasta el momento. Así que se debe modificar el layout de la actividad principal para que el recycler view sea hijo de un elemento de un refresh layout.

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

7. Implementar la escucha OnRefreshListener

Una vez indicado el hijo del refresh layout, procederemos a manejar el evento de refresco. La idea es sobrescribir el método onRefresh() de la escucha OnRefreshListener, el cual es el encargado de dictaminar las acciones que se ejecutarán, cuando la señal se haya concretado en la interfaz.

Usa el método setOnRefreshListener() de la instancia SwipeRefreshLayout para asignar la escucha construida (bien sea anónimamente o implementando la interfaz sobre la actividad principal):

private SwipeRefreshLayout refreshLayout;
..
// Obtener el refreshLayout
refreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefresh);
// Iniciar la tarea asíncrona al revelar el indicador
refreshLayout.setOnRefreshListener(
new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
new HackingBackgroundTask().execute();
}
}
);

Al ser ejecutado onRefresh() se está iniciando una tarea asíncrona que realiza la actualización del adaptador y además simula el retardo de la carga cuando se retarda el hilo con el método sleep().

private class HackingBackgroundTask extends AsyncTask<Void, Void, List<Lista>> {
static final int DURACION = 3 * 1000; // 3 segundos de carga
@Override
protected List doInBackground(Void... params) {
// Simulación de la carga de items
try {
Thread.sleep(DURACION);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Retornar en nuevos elementos para el adaptador
return ConjuntoListas.randomList(CANTIDAD_ITEMS);
}
@Override
protected void onPostExecute(List result) {
super.onPostExecute(result);
// Limpiar elementos antiguos
adapter.clear();
// Añadir elementos nuevos
adapter.addAll(result);
// Parar la animación del indicador
refreshLayout.setRefreshing(false);
}
}

La tarea asíncrona HackingAsynTask no recibe parámetros para su funcionamiento ni tampoco unidades de progreso. Pero debido a que vamos a presentar como resultado una lista de objetos Lista en el hilo principal, entonces usamos el tipo List<Lista> como tercer parámetro de entrada.

doInBackGround() procesa el retardo temporal para la simulación de la carga y al final se retorna en una lista aleatoria con el método randonList(). La constante CANTIDAD_ITEMS está definida al inicio de la actividad, la cual especifica que solo se desean 8 ítems por carga.

Luego se implementa onPostExecute() para refrescar los items. Lo primero es limpiar con clear(), luego añadir el resultado con addAll() y finalmente detener la animación del indicador con el método setRefreshing(). Este recibe un parámetro booleano, donde true inicia la animación y false la detiene.

8. Cambiar color de la animación de progreso

Adicionalmente podemos cambiar el color de la animación de progreso a través del método setColorSchemeResource(). Este método recibe una lista indeterminada de enteros que representan el id del recurso establecido en el archivo colors.xml.

// Seteamos los colores que se usarán a lo largo de la animación
refreshLayout.setColorSchemeResources(
R.color.s1,
R.color.s2,
R.color.s3,
R.color.s4
);

Dependiendo del tiempo de carga así mismo se dará espacio para la transición entre los colores usados. Por ejemplo, el código anterior usa 4 colores intermedios de la paleta para Teal en el Material Design. Cada uno de ellos se encuentra en el archivo de recursos para colores:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="s1">#A7FFEB</color>
<color name="s2">#64FFDA</color>
<color name="s3">#1DE9B6</color>
<color name="s4">#00BFA5</color>
</resources>

Y ya para terminar unificamos todo dentro de la actividad principal, donde crearemos el adaptador, obtendremos el recycler view, implementaremos los eventos, etc.

Veamos:

package com.herprogramacion.revistatempor;
import android.os.AsyncTask;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import java.util.List;
public class MainActivity extends ActionBarActivity {

Declarar instancias globales

private RecyclerView recycler;
private ListaAdapter adapter;
private RecyclerView.LayoutManager lManager;
private SwipeRefreshLayout refreshLayout;
private static final int CANTIDAD_ITEMS = 8;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Obtener el Recycler
recycler = (RecyclerView) findViewById(R.id.reciclador);
// Usar un administrador para LinearLayout
lManager = new LinearLayoutManager(this);
recycler.setLayoutManager(lManager);
// Crear un nuevo adaptador
adapter = new ListaAdapter(ConjuntoListas.randomList(CANTIDAD_ITEMS));
recycler.setAdapter(adapter);
// Obtener el refreshLayout
refreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefresh);
// Seteamos los colores que se usarán a lo largo de la animación
refreshLayout.setColorSchemeResources(
R.color.s1,
R.color.s2,
R.color.s3,
R.color.s4
);
// Iniciar la tarea asíncrona al revelar el indicador
refreshLayout.setOnRefreshListener(
new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
new HackingBackgroundTask().execute();
}
}
);
}
private class HackingBackgroundTask extends AsyncTask<Void, Void, List<Lista>> {
static final int DURACION = 3 * 1000; // 3 segundos de carga
@Override
protected List doInBackground(Void... params) {
// Simulación de la carga de items
try {
Thread.sleep(DURACION);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Retornar en nuevos elementos para el adaptador
return ConjuntoListas.randomList(CANTIDAD_ITEMS);
}
@Override
protected void onPostExecute(List result) {
super.onPostExecute(result);
// Limpiar elementos antiguos
adapter.clear();
// Añadir elementos nuevos
adapter.addAll(result);
// Parar la animación del indicador
refreshLayout.setRefreshing(false);
}
}
}

El resultado final se puede ver en la siguiente ilustración:

Aplicación Android con Patrón Swipe Refresh
¿Te gustaría obtener el proyecto en Android Studio completico?, entonces accede al siguiente enlace:

Descargar Código Todos los creditos de los iconos para IconFinder.

James Revelo Urrea - Desarrollador independiente http://www.hermosaprogramacion.com

Fuente: este post proviene de Hermosa Programación, donde puedes consultar el contenido original.
¿Vulnera este post tus derechos? Pincha aquí.
Creado:
¿Qué te ha parecido esta idea?

Esta idea proviene de:

Y estas son sus últimas ideas publicadas:

Recomendamos

Relacionado

informática desarrollo android

Volley es una librería desarrollada por Google para optimizar el envío de peticiones Http desde las aplicaciones Android hacia servidores externos. Este componente actúa como una interfaz de alto nivel, liberando al programador de la administración de hilos y procesos tediosos de parsing, para permitir publicar fácilmente resultados en el hilo principal. En este artículo veremos la guía co ...

informática desarrollo android

Las listas en Android son contenedores supremamente útiles para organizar información en forma vertical y con la capacidad de usar scrolling(desplazamiento) para simplificar su visualización. Esta técnica es muy popular en muchas aplicaciones, ya que permite mostrarle al usuario un conjunto de datos de forma practica y accesible. Si sigues leyendo podrás aprender sobre: La clase ListView Crear un ...

informática desarrollo android

¿Andas buscando como parsear un archivo RSS con formato XML, para incluir contenidos de un sitio web en tu aplicación Android? ¿Necesitas ideas para crear una app lectora de Rss como Feedly, Flipboard o Flyne? Pues bien, en este tutorial verás cómo alimentar una lista de elementos con las noticias del sitio web forbes.com desde su feed con formato RSS a través de las tecnologías Volley y Simple Fr ...

informática desarrollo android

Las listas en Android son contenedores supremamente útiles para organizar información en forma vertical y con la capacidad de usar scrolling(desplazamiento) para simplificar su visualización. Esta técnica es muy popular en muchas aplicaciones, ya que permite mostrarle al usuario un conjunto de datos de forma practica y accesible. Si sigues leyendo podrás aprender sobre: La clase ListView Crear un ...

informática desarrollo android

Este artículo te explicará el uso del Navigation Drawer en Android para crear una navegación a través de un Menú deslizante. Verás como implementar un Drawer Layout para el diseño. Aprenderás a manejar los eventos relacionados. Y también a complementar su funcionamiento con la action bar mediante un Action Bar Drawer Toggle. CONTENIDO ¿Cómo crear un menú deslizante con un Navigation Drawer? Ejem ...

informática desarrollo android

Este artículo te explicará el uso del Navigation Drawer en Android para crear una navegación a través de un Menú deslizante. Verás como implementar un Drawer Layout para el diseño. Aprenderás a manejar los eventos relacionados. Y también a complementar su funcionamiento con la action bar mediante un Action Bar Drawer Toggle. CONTENIDO ¿Cómo crear un menú deslizante con un Navigation Drawer? Ejem ...

informática material design desarrollo 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. CONTENIDO Crear lista ...

informática android aplicaciones ...

En este artículo descubriremos el poder de los fragmentos en el desarrollo de aplicaciones Android. Entenderemos su concepto y propósito, el ciclo de vida que poseen, las ventajas que tiene usarlos y como crearlos en nuestros proyectos en Android Studio de forma declarativa y programática. ¿Qué es un fragmento? La necesidad de usar fragmentos nace con la versión 3.0 (API 11) de Android debido a lo ...

informática android aplicaciones ...

En este artículo descubriremos el poder de los fragmentos en el desarrollo de aplicaciones Android. Entenderemos su concepto y propósito, el ciclo de vida que poseen, las ventajas que tiene usarlos y como crearlos en nuestros proyectos en Android Studio de forma declarativa y programática. ¿Qué es un fragmento? La necesidad de usar fragmentos nace con la versión 3.0 (API 11) de Android debido a lo ...

informática desarrollo android

IMG.displayed{display:block;margin-left:auto;margin-right:auto} En este articulo estudiaremos las características y el uso de la Action Bar (Barra de acción) en el desarrollo Android. Veremos su anatomía, como crear un archivo de diseño para ella, como ejecutar las acciones una vez presionado sus opciones y otras características relevantes. Indice: Funciones del Action Bar Anatomía de la Action ...