sábado, 21 de junio de 2014

Añadir el patrón Pull to Refresh a nuestra App


Uno de los patrones de interacción que vemos cada vez más es el de Pull To Refresh. Consiste en que el usuario realiza una acción de pull (tirar) vertical hacia abajo para ejecutar una actualización del contenido que esta viendo. Podemos verlo en aplicaciones móviles como gestores de correo, Google+ o Facebook, es decir, en aplicaciones que muestran contenido obtenido de forma remota y que por lo tanto necesita ser actualizado. Es una forma sencilla e intuitiva de que el usuario realice una actualización manual.

Aunque siempre puedes implementar tu mismo este patrón, existen varias bibliotecas que nos simplificarán la vida bastante. Yo he elegido ActionBar-PullToRefresh. Es muy fácil de usar y de personalizar pero, como se puede ver en su página de GitHub, ya no esta bajo mantenimiento. Otro aspecto a tener en cuenta es que solo funciona para versiones de Android igual o superiores a 4.0 (API 14).


Un ejemplo sencillo:

Vamos a aplicar el patrón sobre un Activity que despliega una lista, dejando la
personalización para mas adelante y trabajando con los valores por defecto. En el caso de los Fragment la inicialización es un poco diferente pero los cambios son mínimos.

Primero debemos incluir un PullToRefreshLayout como layout raíz de la interfaz de nuestra Activity (MainActivity):
<uk.co.senab.actionbarpulltorefresh.library.PullToRefreshLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/my_ptr_layout"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <ListView
    android:id="@+id/my_listView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >
  </ListView>

</uk.co.senab.actionbarpulltorefresh.library.PullToRefreshLayout>

PullToRefreshLayout solo funciona por defecto con:
  • Clases que heredan de AbsListView (como ListView o GridView)
  • ScrollView
  • WebView

Para cualquier otro tendremos que implementar nuestro propio ViewDelegate.

Ahora inicializaremos PullToRefreshLayout en el código de MainActivity:
public class MainActivity extends Activity{
  private View txt;
  private PullToRefreshLayout pullLayout;
  private final OnRefreshListener onRefreshListener =
    new OnRefreshListener(){
      @Override
      public void onRefreshStarted(View v){
        // Aqui realizaremos la actualización
      }
    };

  @Override
  protected void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    pullLayout = (PullToRefreshLayout) findViewById(R.id.my_ptr_layout);
    // Inicializamos el PullToRefreshLayout
    ActionBarPullToRefresh.from(this)
      // Marcamos todos los hijos para que puedan recibir la accion de pull
      .allChildrenArePullable()
      // Le indicamos el OnRefreshlistener
      .listener(onRefreshListener)
      // Terminamos la inicializacion
      .setup(mPullToRefreshLayout);
    //...
  }
  //...
}


Hay que tener en cuenta que el método onRefreshStarted del listener se ejecutará sobre la hebra principal así que lo mejor es que lancemos algún tipo de AsyncTask o Loader. Para parar la animación de actualización llamaremos al método setRefreshComplete de nuestro PullToRefreshLayout:
@Override
public void onRefreshStarted(View view) {
  new AsyncTask<Void, Void, Void>() {
    @Override
    protected Void doInBackground(Void... params) {
    //Aqui realizamos la actualización del contenido
      return null;
    }

    @Override
    protected void onPostExecute(Void result) {
      super.onPostExecute(result);
      //...
      pullLayout.setRefreshComplete();
    }
  }.execute();
}


Con esto ya tenemos completo un ejemplo sencillo de uso de esta biblioteca.


Personalización

Ya hemos visto lo fácil que es usar la biblioteca. Ahora veremos lo fácil que es cambiar el comportamiento de la barra de actualización.

En la biblioteca tenemos la clase Options. Durante la inicialización podemos darle una instancia de esta clase para indicarle distintos elementos de configuración como:
  • headerLayout: Layout (indicado por el identificador del recurso) que se usará para la barra de actualización.
  • headerTransformer: El HeaderTransformer que se encargará de cambiar la barra de actualización según su estado (lo veremos mas adelante).
  • headerInAnimation: Animación que se usará al mostrar la barra de actualización.
  • headerOutAnimation: Animación que se usará al esconder la barra de actualización.
  • refreshScrollDistance: Distancia de pulling necesaria para que se dispare la actualización. Se especifica en porcentaje (de 0.0 a 1.0) con respecto a la altura de la vista a la que se hará pull. Por ejemplo 0.5f significa que solo tenemos que recorrer la mitad de la altura para disparar la actualización.
  • refreshOnUp: Por defecto la actualización se dispara cuando se recorre la distancia de pulling. Si activamos este elemento el usuario tendrá que levantar el dedo después de recorrerla, lo que le da la posibilidad de "arrepentirse" y volver atrás.
  • refreshMinimize: Esconder la barra de actualización durante esta. Es útil cuando la actualización es muy larga y no queremos tapar indefinidamente el ActionBar.
  • refreshMinimizeDelay: Es el tiempo que se esperará antes de esconder la barra de actualización.

Para aplicar nuestras opciones tendremos que actualizar el código de inicialización que hemos visto antes:
@Override
protected void onCreate(Bundle savedInstanceState){
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  pullLayout = (PullToRefreshLayout) findViewById(R.id.my_ptr_layout);
  Options options = Options.create()
    .scrollDistance(.5f)
    .headerLayout(R.layout.customised_header)
    .headerTransformer(new CustomisedHeaderTransformer())
    .build();

  // Inicializamos el PullToRefreshLayout
  ActionBarPullToRefresh.from(this)
    // Le indicamos el objeto options a usar
    .options(options)
    .allChildrenArePullable()
    .listener(onRefreshListener)
    .setup(mPullToRefreshLayout);
  //...
}


La instancia de la clase CustomizedHeaderTransformer es la encargada de actualizar la barra según el estado de la actualización. Hereda de la clase abstracta HeaderTransformer y debe implementar los siguientes métodos:
  • boolean showHeaderView(): Se llama cuando la barra debe mostrarse.
  • boolean hideHeaderView(): Se llama cuando la barra debe esconderse.

Además de esos dos métodos se pueden implementar los siguientes:
  • onViewCreated(Activity activity, View headerView): Se llama cuando se ha creado el View de la barra de actualización.
    • activity: Activity a la que esta asociada la barra.
    • headerView: Barra de actualización creada.
  • onReset(): Se llama cuando la barra tiene que ser reiniciada.
  • onPulled(float perc): Se llama cuando el usuario realiza la acción de pulling.
    • perc: Porcentaje de distancia de pulling.
  • onRefreshStarted(): Se llama cuando se dispara la actualización.
  • onReleaseToRefresh(): Se llama cuando el usuario ha recorrido toda la distancia de pulling pero aún necesita levantar el dedo.
  • onRefreshMinimized(): Se llama cuando la actualización está llevando más tiempo que el especificado en refreshMinimizeDelay.
  • onConfigurationChanged(Activity activity, Configuration conf): Se llama cuando la configuración de la Activity a la que está asociada la barra cambia.
    • activity: Activity a la que esta asociada la barra.
    • conf: Nueva configuración.

Como hemos visto usar esta biblioteca es muy sencillo y nos da una gran libertad a la hora de personalizar el comportamiento de la barra de actualización. Con esto podremos implantar el patrón Pull to Refresh a nuestras aplicaciones.








No hay comentarios:

Publicar un comentario