Con la llegada de Android 5 Lollipop llegaron una serie de novedades a la plataforma que voy a intentar repasar en este y próximos artículos. En vamos a empezar viendo el nuevo widget ReciclerView. El widget ReciclerView viene incluido dentro de la nueva versión actualizada de la libreria de soporte para versiones antiguas appcompat v7. Viene para sustituir a los widget ListView y GridView.
Introducción a ReciclerView
Es un contenedor de colección elementos en forma de lista pero es más flexible y oferce mejor rendimiento que ListView. 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 un origen datos 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 reutilizar los views y pedir el nuevo contenido al adapter, se encarga de reciclar los elementos que dejan de ser visibles para el usuario al hacer scroll por el contenido de otros que son visibles.
En Lollipop vienen 3 LayoutManager :
- LinearLayoutManager muestra los items en forma de lista horizontal o vertical
- GridLayoutManager muestra los items en forma de grid
- StaggeredGridLayoutManager muestra los items en forma de grid con celdas no uniformes.
Ejemplo
Vamos a ver un ejemplo de un ReciclerView que va a ser un grid de imagenes.Dependencias
En el fichero build.gradle del modulo de la aplicación tenemos que añadir las dependencias que vamos a necesitar.dependencies { ... compile 'com.android.support:appcompat-v7:22.0.0' compile 'com.android.support:recyclerview-v7:22.0.+' compile 'com.squareup.picasso:picasso:2.5.2' }
Picasso es una libería para descargar imágenes pero se queda fuera del alcance de este artículo, asi que no entraré en detalles.
Layouts
Vamos a tener 3 layouts:activity_items.xml:
Nuestro ejemplo es sencillo a si que solo consta de un Framelayout donde visualizaremos despues el fragment con el contenido. Es una buena práctica en Android utilizar fragments para reutilización de vistas entre diferentes resoluciones.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container"
android:layout_width="match_parent" android:layout_height="match_parent"
tools:context=".ItemsActivity" tools:ignore="MergeRootFrame" />
fragment_items.xml:
El layout del fragment va a ser donde vamos a tener realmente el RecyclerView.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ItemsActivity$ItemsFragment">
<android.support.v7.widget.RecyclerView
android:id="@+id/items_recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
items_item.xml:
El layout para cada elemento del RecyclerView, que consta de una imagen por el momento.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/itemImage"
android:layout_width="@dimen/image_width"
android:layout_height="@dimen/image_height" />
</LinearLayout>
Modelo
El modelo es bastante sencillo y de momento para este artículo solo ultilizaremos el getter image.public class Item { String title; String description; String imageUrl; public Item(String title, String description, String imageUrl) { this.title = title; this.description = description; this.imageUrl = imageUrl; } }
Activity
El activity es bastante sencillo también solo visualiza el fragment.public class ItemsActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_items); if (savedInstanceState == null) { getSupportFragmentManager().beginTransaction() .add(R.id.container, new ItemsFragment()) .commit(); } } }
Fragment
El fragment, es donde esta realmente esta parte del trabajo, crea los datos a representar, configura el RecyclerView y el adapter.public class ItemsFragment extends Fragment { private RecyclerView recyclerView; private RecyclerView.Adapter adapter; private RecyclerView.LayoutManager layoutManager; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_items, container, false); recyclerView = (RecyclerView) rootView.findViewById(R.id.items_recycler_view); //poner a true si cambios en el contenido no supone //cambios en el tamaño del control, esto mejora rendimiento recyclerView.setHasFixedSize(true); //usamos un GridLayoutManager con 2 columnas layoutManager = new GridLayoutManager(rootView.getContext(),2); recyclerView.setLayoutManager(layoutManager); adapter = new ItemsAdapter(createItems()); recyclerView.setAdapter(adapter); return rootView; } private Item[] createItems(){ String commonPath = "http://lorempixel.com/400/400/people/"; Item[] items = new Item[] { new Item(null,null,commonPath + "1"), new Item(null,null,commonPath + "2"), new Item(null,null,commonPath + "3"), new Item(null,null,commonPath + "4"), new Item(null,null,commonPath + "5"), new Item(null,null,commonPath + "6"), new Item(null,null,commonPath + "7"), new Item(null,null,commonPath + "8"), new Item(null,null,commonPath + "9"), new Item(null,null,commonPath + "10")}; return items; } }
Adapter
El Adapter es el encargado de representar los datos, fijaros la integración que tiene ahora un adapter con el ViewHolder, en versiones anteriores a Lollipop era bastante manual la aplicación de este patrón.public class ItemsAdapter extends RecyclerView.Adapter{ private Item[] items; public static class ViewHolder extends RecyclerView.ViewHolder { public ImageView imageView; public ViewHolder(View v) { super(v); imageView = (ImageView) v.findViewById(R.id.itemImage);; } } public ItemsAdapter(Item[] items) { this.items = items; } // crea una nueva vista(invocado por el layout manager) @Override public ItemsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { //creamos la nueva imagen View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_items, parent, false); ViewHolder vh = new ViewHolder(v); return vh; } // Reemplaza el contenido de una vista (invocado por el layout manager) @Override public void onBindViewHolder(ViewHolder holder, int position) { Item item = items[position]; //cargamos la imagen con picasso Picasso.with(holder.imageView.getContext()) .load(item.imageUrl) .into(holder.imageView); } @Override public int getItemCount() { return items.length; } }
Concusiones
A partir de Lollipop existe un nuevo widget llamado RecyclerView que debe ser el que utilicemos para representar datos en forma de lista. Esta más optimizado que el antiguo ListView. Para configurarlo es parecido a ListView la diferencia es que viene integrado con el patrón ViewHolder y existe una nueva clase LatoutManager encargada de la gestion de reciclado.Código fuente en GitHub - tag 0.1
Libros relacionados
Android Programming: The Big Nerd Ranch GuideAndroid Programming In a Day!: The Power Guide for Beginners In Android App Programming
No hay comentarios:
Publicar un comentario