Lollipop new features: manejando el click en los elementos del RecyclerView

jueves, 14 de mayo de 2015


En este artículo vamos a continuar con las novedades de Lollipop, vamos a continuar con la aplicación que empezamos en el anterior artículo sobre RecyclerView. El control RecyclerView a diferencia de ListView no tiene un OnClickListener y vamos a tener que implementarlo nosotros.

Introducción

Ahora debe ser la propia celda la que comunique cuando se ha hecho click sobre ella, a mi me gusta añadir un interface OnItemClickListener en el Adapter, con un método onClick invocado cuando se hace click en la vista del elemento desde el ViewHolder. De esta forma la responsabilidad de que hacer cuando se produce el click en un elemento queda ajeno al ViewHolder y el Adapter. Será el activity o el fragment el que decidirá lo que hay que hacer, en arquitecturas tipo Clean notificaría al ViewPresenter la acción a realizar.

El método onClick del listener va a tener dos parámetros, uno la vista donde se ha hecho click y la posición que ocupa el elemento en el adapter, de forma que se pueda acceder al modelo que representa la vista si se necesita.

El método onClick podría llevar solo un parámetro directamente con el modelo, de hecho veréis este tipo de solución por internet, pero a mi me gusta dejarlo más abierto y menos dependiente del modelo de la aplicacón por si se necesitará hacer algo con la vista sobre la que se hace click como cambiar el layout o hacer una transición como veremos en artículos posteriores.

Ejemplo

Bueno vamos al lío.

Un listener en el adapter

Añadimos un interface para el listener y el objeto listener en el adapter.

public class ItemsAdapter extends RecyclerView.Adapter {
  
  .
  .
  .
  
  private static OnItemClickListener onItemClickListener;

  .
  .
  .

  public static interface OnItemClickListener {
      public void onItemClick(View view, int position);
  }

  .
  .
  .
}


Se invoca el listener cuando se hace click en la vista

Capturamos el click de la vista root del item y cuando se dispara el callback invocamos el onClick del listener del adapter.

public class ItemsAdapter extends RecyclerView.Adapter {
  
  .
  .
  .
  
  private static OnItemClickListener onItemClickListener;

  .
  .
  .

  public static interface OnItemClickListener {
      public void onItemClick(View view, int position);
  }

  .
  .
  .

  public static class ViewHolder extends RecyclerView.ViewHolder {
      public ImageView imageView;

      public ViewHolder(View itemRootView) {
          super(itemRootView);
          imageView = (ImageView) itemRootView.findViewById(R.id.itemImage);

          itemRootView.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View view) {
                  int position  = ViewHolder.super.getAdapterPosition();
                  onItemClickListener.onItemClick(view,position);
              }
          });
      }
  }
}

Asignamos el onItemClickListener al adapter

Desde el activity o fragment, en nuestro caso fragment, asignamos un listener al adapter y en el callback onClick vamos a obtener el item seleccionado mediante la posición y abrimos un activity de detalle del item.

public class ItemsFragment extends Fragment {
    .
    .
    .

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
       .
       .
       .

        ((ItemsAdapter) adapter).setOnItemClickListener(new ItemsAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                Item item = items[position];

                Intent intent = new Intent(getActivity(), ItemDetailActivity.class);
                intent.putExtra("item", item);
 
                startActivity(intent);
            }
        });

        .
        .
        .
    }

    .
    .
    .
}

Concusiones

El nuevo widget RecyclerView que viene en la version Lollipop, no tiene un listener para cuando se hace click en un elemento, tenemos que implementar una solución manual. Hemos visto una forma de hacerlo que consiste en añadir el listener al adapter de forma que no sobrecargamos de responsabilidades el adapter ya que notifica mediante su listener cuando se hace click en un elemento pero no se responsabiliza de la acción a realizar en ese momento.

Código fuente en GitHub - tag 0.2

Libros relacionados

Android Programming: The Big Nerd Ranch Guide
Android Programming In a Day!: The Power Guide for Beginners In Android App Programming

No hay comentarios:

Publicar un comentario