Buenas tardes, en este tutorial vamos a ver 2 elementos. Uno de ellos ya lo hemos visto en entradas anteriores, los Fragment, y el otro es la primera vez que escribo sobre el, y es llamado ViewPager.
Un ViewPager es un elemento que nos permitirá deslizarnos hacia la derecha o a la izquierda en nuestra pantalla, mostrando diferente información. Se suelen usar normalmente con Fragment aunque también podemos usarlos sin ellos, usando layouts creados por nosotros mismos, pero en el caso de los Fragment, estos nos permiten controlar su ciclo de vida.
Vamos a ponernos manos a la obra:
-
Creación del Proyecto
EL primer paso es crear un proyecto de aplicación de Android, o Android Application Project como veremos en el IDE. Para ello nos dirigimos a File->New->Android Application Project. En caso de que no veamos esta opción en la lista, nos dirigimos a “Other”, y en la ventana que nos aparezca lo buscamos, o si lo deseamos podemos filtrar la lista introduciendo “Android” en el campo de texto. Una vez que lo tengamos localizado, lo marcamos y pinchamos en aceptar.
Nos aparecerá entonces el asistente de creación del proyecto. En la primera ventana nos va a aparecer la opción de asignar un nombre a nuestra aplicación y a nuestro proyecto. En mi caso no me he complicado y le he puesto de nombre “EjemploViewPager”, aunque es lo de menos y podeis darle el nombre que deseeis. El resto podemos dejarlo como está.
A medida que avancemos por el asistente, nos encontraremos con la creación de nuestra primera Activity en la cual podremos darle nombre, al igual que su layout. En mi caso la he llamado “ViewPagerActivity”, y su layout se llama “activity_view_pager.xml”.
Una vez tengamos nuestro asistente finalizado, podremos seguir con la construcción de nuestra aplicación.
-
FragmentA
Para comenzar vamos a crear una nueva clase llamada “FragmentA” que hereda de la clase Fragment. Este Fragment será normal, y mostraremos en el únicamente 2 textos. A continuación vamos a ver su layout, el cual crearemos y, en mi caso, lo he llamado “fragmenta.xml”:
<?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" android:gravity="center" android:orientation="vertical" android:padding="20dp" > <TextView android:id="@+id/tvTexto1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Fragment 1" android:textSize="30sp" android:textStyle="bold" /> <TextView android:id="@+id/tvTexto2" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Esto es un Fragmento normal" android:textSize="20sp" /> </LinearLayout>
Como vemos tenemos 2 elementos TextView que muestran un texto estático sin ninguna funcionalidad, meramente lo usaremos para identificarlo.
El código de esta clase no es nada del otro mundo tampoco, ya que lo único que haremos es sustituir el método onCreateView en el que retornaremos la View creada:
package sekth.droid.viewpager.Fragments; import sekth.droid.viewpager.R; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; public class FragmentA extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // TODO Auto-generated method stub return inflater.inflate(R.layout.fragmenta, container, false); } }
-
FragmentB
Este otro Fragment va a tener otra funcionalidad, ya que lo crearemos pero no heredará de la clase Fragment, sinó de la clase ListFragment, ya que vamos a poner una lista con elementos en el, parecido a la aplicación de la Play Store de Google. En mi caso lo he llamado “FragmentB”, y su archivo layout el cual vamos a crear lo llamaré “fragmentb.xml”. Vemos el código de su layout a continuación:
<?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" android:orientation="vertical" > <ListView android:id="@+id/android:list" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout>
Lo único que haremos es agregar un elemento ListView, el cual cargaremos mas tarde en el código del FragmentB.
Por otro lado, el código java de la clase FragmentB, además de sustituir el método onCreateView del cuál ya hemos visto su utilidad, sustituiremos también el método onCreate, donde cargaremos el ListView. Vemos su código a continuación, el cuál explicaremos a continuación:
package sekth.droid.viewpager.Fragments; import sekth.droid.viewpager.R; import sekth.droid.viewpager.Clases.Content; import android.os.Bundle; import android.support.v4.app.ListFragment; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; public class FragmentB extends ListFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // TODO Auto-generated method stub return inflater.inflate(R.layout.fragmentb, container, false); } @Override public void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); // Según el resultado, lo cargaremos con datos diferentes int tipoLista = (int) (Math.random() * 3); switch (tipoLista) { case 0: setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, Content.smartphoneSO)); break; case 1: setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, Content.computerSO)); break; case 2: setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, Content.androidVersion)); } } }
Como vemos, en el método onCreate vamos a cargar las ListView. En mi caso, no quiero rellenar varias ListView con el mismo contenido, por lo que según el número aleatorio, se cargará con un contenido distinto.
-
Content
En esta clase lo único que haré es crear 3 arrays de String, con contenido diferente para poder llenar las diferentes ListView. Su código es mostrado a continuación:
package sekth.droid.viewpager.Clases; public class Content { public static final String[] smartphoneSO = { "Android", "Windows Phone", "iOS", "Symbian", "Blackberry" }; public static final String[] computerSO = { "Windows", "Ubuntu", "Mac OSX", "Kubuntu", "Solaris", "Chrome OS" }; public static final String[] androidVersion = { "Froyo", "Gingerbread", "Ice Cream Sandwich", "Jelly Bean", "Cupcake", "Éclair", "HoneyComb", "Key Lime" }; }
Como vemos no ofrece mucha utilidad, es solo para tener algún lugar donde crear datos para simular las listas.
-
-
MyPagerAdapter
Para poder crear el ViewPager vamos a tener que apoyarnos en una clase que nos sirva de “adaptador”, como cualquier otro elemento que necesite adaptar una fuente de datos, ya sea un ListView o un Grid. Para ello vamos a crear una nueva clase llamada MyPagerAdapter, la cual va a heredar de la clase FragmentStatePagerAdapter. Aunque podemos heredar de otra clase, como por ejemplo FragmentPagerAdapter, la clase FragmentStatePagerAdapter trabaja mejor cuando tenemos una gran cantidad de Fragment que sean de tipo ListFragment, por tanto nos ofrece mayor rendimiento a la hora de implementarlo. Cuando una página no es visible, el Fragment es completamente destruido, guardando solo el estado del Fragment. Esto permite a requerir un uso menor de memoria.
Vamos a ver su código a continuación:
package sekth.droid.viewpager.Adapter; import java.util.List; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentStatePagerAdapter; public class MyPagerAdapter extends FragmentStatePagerAdapter { private List<Fragment> fragments; public MyPagerAdapter(FragmentManager fm, List<Fragment> fragments) { super(fm); // TODO Auto-generated constructor stub this.fragments = fragments; } @Override public Fragment getItem(int position) { // TODO Auto-generated method stub return fragments.get(position); } @Override public int getCount() { // TODO Auto-generated method stub return fragments.size(); } }
Vamos a ver cada uno de sus métodos:
-
public MyPagerAdapter(FragmentManager fm, List fragments)
Este método es el constructor, y en el guardaremos una referencia a una lista de fragments que recogemos de los argumentos del método:
public MyPagerAdapter(FragmentManager fm, List<Fragment> fragments) { super(fm); // TODO Auto-generated constructor stub this.fragments = fragments; }
-
public Fragment getItem(int position)
Este método se encarga de retornar la posición del Fragment actual:
@Override public Fragment getItem(int position) { // TODO Auto-generated method stub return fragments.get(position); }
-
public int getCount()
Este método será el encargado de retornar la cantidad de Fragment que tiene el adapter:
@Override public int getCount() { // TODO Auto-generated method stub return fragments.size(); }
-
-
ViewPagerActivity
Esta es nuestra Activity, la cuál se creó junto a nuestro proyecto. Su archivo layout es el siguiente:
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="match_parent" />
Como vemos solo tenemos un único elemento, el cuál sacamos de la librería de soporte.
A continuación vamos a ver el código java de nustra Activity:
package sekth.droid.viewpager.Activity; import java.util.ArrayList; import java.util.List; import sekth.droid.viewpager.R; import sekth.droid.viewpager.Adapter.MyPagerAdapter; import sekth.droid.viewpager.Fragments.FragmentA; import sekth.droid.viewpager.Fragments.FragmentB; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.view.ViewPager; public class ViewPagerActivity extends FragmentActivity { MyPagerAdapter mPagerAdapter; ViewPager mviewPager; private List<Fragment> listaFragments; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_view_pager); // Creamos una lista de Fragments listaFragments = new ArrayList<Fragment>(); listaFragments.add(new FragmentB()); listaFragments.add(new FragmentA()); listaFragments.add(new FragmentB()); listaFragments.add(new FragmentA()); listaFragments.add(new FragmentB()); // Creamos nuestro Adapter mPagerAdapter = new MyPagerAdapter(getSupportFragmentManager(), listaFragments); // Instanciamos nuestro ViewPager mviewPager = (ViewPager) findViewById(R.id.viewPager); // Establecemos el Adapter mviewPager.setAdapter(mPagerAdapter); } }
Lo único que haremos es crear una List en el que vamos a añadir diferentes Fragment. En este caso vamos a añadir 3 FragmentB y 2 FragmentA para que veamos las diferencias en la aplicación.
Una vez tenemos la List creada, vamos a instanciar nuestra clase MyPagerAdapter pasandole como argumentos el FragmentManager que obtenemos mediante el método getSupportFragmentManager() y la List que acabamos de crear. Una vez hecho esto, instanciaremos nuestro ViewPager y le estableceremos nuestro Adapter.
Con esto tendremos finalmente nuestra aplicación montada y creada, tendremos una especie de Paginación, en la cual tendremos diferente información, y cada página tiene su propio ciclo de vida ya que son Fragment.
Podremos observar también que posiblemente que las listas que nos aparezcan no sean iguales, ya que mediante el uso de la superclase FragmentStatePagerAdapter hace que se destruyan los Fragment al no aparecer en pantalla, por tanto al volver a cargar los ListView, se vuelve a ejecutar el código en el cual se asigna una fuente de datos. Esto podremos resolverlo guardando el estado del Fragment y comprobando antes de crearlo si hay algo guardado para reestablecerlo.
Vemos unas capturas de pantalla de como queda finalmente:
Ahora vemos un video donde podemos ver finalmente la aplicación en ejecución:
Con esta entrada hemos aprendido a implementar el ViewPager junto a Fragment en nuestros proyectos, lo cual nos puede ser de mucha utilidad.
El código de ejemplo se puede descargar de aquí.
Sin más, cualquier aporte o corrección es bienvenida.
Saludos!!!