miércoles, 21 de septiembre de 2011

Ejemplo con ViewPager en Android

Hola que tal a todos, últimamente he estado un poco ausente por varios proyectos y ocupaciones pero ya espero estar de vuelta posteando seguido. En esta ocasión les quiero compartir un ejemplo de como utilizar el ViewPager en una aplicación android. Esta vista se ha vuelto muy popular últimamente dentro de Android, el nuevo Market la utiliza para cambiar entre secciones, la aplicación Talk la utiliza para cambiar entre chats activos, entre otros; si no están familiarizados con esta vista o simplemente no la reconocen por el nombre solo basta con mirar este post y ver la ultima imagen del Android Market. ViewPager es esa vista que nos permite hacer un swap con nuestro dedo (deslizarlo de lado a lado de la pantalla) y cambiar entre vistas activas en la aplicación.

Bueno ahora si manos a la obra, lo primero que tenemos que tomar en cuenta es que ViewPager es una clase que hereda de Vista, se puede agregar a los archivos xml de layout de android, mas sin embargo no se encuentra dentro de las clases base de Android OS, esta clase se introdujo con la llegada de las actualizaciones de HoneyComb y los ingenieros de Google la agregaron dentro del paquete de compatibilidad para versiones anteriores. Por lo tanto es necesario que utilicemos nuestro AVD Manager e instalar el paquete de compatibilidad desde el repositorio de android. Una vez que este instalado solo es necesario configurar nuestro proyecto para que utilice este paquete. Para hacer esto solo damos click secundario en el proyecto de eclipse y dentro de Android Tools damos click en Add Compatibility Library.


Una vez que nuestro proyecto este configurado ya podemos hacer uso de esta clase dentro de nuestros archivos xml de layout, pero recuerden que como esta no es una clase del sistema base de android es necesario agregarla a nuestros xml como si fuera una vista personalizada en android. Por lo tanto nuestro archivo de layout de ejemplo (main.xml) quedaría de esta manera.


La clase ViewPager requiere un adaptador (una clase que herede de ViewPagerAdapter) el cual sera encargado de manejar las vistas y la interacción del usuario con cada una de las "paginas", lo mas sencillo de implementar es una clase que extienda de FragmentPagerAdapter la cual lanzara el Fragment necesario para  cada pagina cuando sea necesario, con esto podemos manejar dentro de nuestros fragmentos todas las acciones del usuario que se generen dentro de la pagina activa en la aplicación. Para este ejemplo se creo una clase llamada MyFragmentPagerAdapter el cual realizara la tarea de almacenar fragmentos y regresar el indicado cuando la aplicación lo requiera. Nuestra clase adaptador se ve así, lo único que hace es almacenar Fragmentos en una lista y regresar los cuando sea necesario.




Este adaptador se llena con diferentes fragmentos, los cuales lo único que harán sera desplegar un componente reloj con un color de fondo definido. Para esto vamos a crear una clase nueva que extenderá la clase Fragment y un nuevo archivo layout el cual sera desplegado en nuestro fragmento, este archivo se utilizara en el método onCreateView del fragmento para generar y almacenar la vista que sera desplegada en cada una de las paginas. Estos archivos se ven de la siguiente manera.


Y ya por ultimo en nuestra actividad principal, la cual debe de extender de FragmentActivity en lugar de Activity solo es necesario crear los fragmentos necesarios y el adaptador para establecerlo en nuestro layout principal. Nuestra clase principal se debe de ver de esta manera.

Se puede observar que lo único que hace nuestra clase es establecer nuestro main layout (main.xml), luego retrae el ViewPager de nuestra vista para después crearle un adaptador con 3 nuevos fragmentos y establecerlo al Pager con el método setAdapter(..). Con esto la secuencia que seguirá la aplicación es crear cada uno de los fragmentos (PlainColorFragment) y cuando el Pager vaya a desplegar una pagina llamara al método getView del fragmento correspondiente (recuerden que la vista ya ha sido creada con el método noCreateView) para ser desplegado dentro de la pagina.

Con estas sencillas clases ya podemos hacer Swap con nuestro dedo e ir cambiando de vistas de forma dinámica y entre diferentes funcionalidades de nuestra aplicación. Al final les dejo las imágenes de como se ve esta aplicación funcionando en el android emulator y también el link hacia el repositorio de github desde donde pueden descargar el código completo para que lo prueben y extiendan la aplicación a su gusto. En posts posteriores extenderemos esta aplicación para manejar eventos de usuario y un poco mas de funcionalidad.

Un saludo a todos y espero que este post sea de ayuda.

Código Fuente completo: https://github.com/ti3r/view_pager_test

Imágenes del ejemplo:



18 comentarios:

  1. Muchísimas gracias por el tutorial. Funciona perfecto.

    Un saludo y gracias de nuevo.

    ResponderEliminar
  2. muchas gracias muy bueno el post!

    ResponderEliminar
  3. Amigo, muchas gracias

    Como comienzo el viewpager desde el fragment # 2??? En tu ejemplo sería comenzar con el verde de tal manera que pueda ir a la izquierda hacia el rojo o a la derecha, el azul.

    Gracias

    ResponderEliminar
    Respuestas
    1. Que tal Johan, se puede seleccionar la pagina por medio de codigo. el metodo es setCurrentItem creo, o setCurrentPage. Con esto puedes seleccionar la pagina a iniciar despues de establecer el adapter utiliza
      setCurrentItem(1) y eso seleccionara la pagina deseada antes de ser mostrada.
      Espero te funcione. Saludos

      Eliminar
    2. Gracias, funciono con el setCurrentitem

      Slds,

      Eliminar
  4. En eclipse no me deja sobreescribir el método onCreateView, me indica que tengo que eliminar la etiqueta @Override, ¿Cuál podría ser el problema?

    ResponderEliminar
    Respuestas
    1. Creo que no tienes configurado correctamente el java compiler. Que version de JDK estas utilizando para ejecutar eclipse? Si eliminas la anotacion @Override no es gran cosa aun asi el compilador debe de detectar que es un override. Hazlo y ve que te arroja
      Espero te funcione

      Eliminar
  5. Hola, me ha parecido estupendo este ejemplo. Muchas gracias por dedicarle ese tiempo.

    Me preguntaba si podrías hacer un ejemplo algo más complejo, no me ha quedado muy claro si se pueden personalizar los fragments de manera dinamica, veo el cambio en el color de fondo, pero ¿existiría la posibilidad de tocar los atributos del reloj en cada fragment?
    En mi caso quiero poner un imageview y cambiar la imagen de cada fragment, pero no hayo la forma de acceder el ImageView contenido en el LinearLayout de color_layout.
    Agradecería cualquier ayuda en esta direccion. Gracias!

    ResponderEliminar
    Respuestas
    1. Que tal Oscar. Me da gusto que el blog te sea de ayuda. De hecho. Dentro de cada uno de los fragmentos se puede tener cualquier layout y acceder a el y a sus ccomponentes. Puedes hacer hacer que cada fragmento sea independiente y maneje sus eventos internamente o retraer el fragmento desde el viewpager a tu actividad y enviar eventos. Preparare un ejemplo mas complejo el fin de semana y lo compartire en el blog.
      Saludos

      Eliminar
    2. Que tal Oscar. Me da gusto que el blog te sea de ayuda. De hecho. Dentro de cada uno de los fragmentos se puede tener cualquier layout y acceder a el y a sus ccomponentes. Puedes hacer hacer que cada fragmento sea independiente y maneje sus eventos internamente o retraer el fragmento desde el viewpager a tu actividad y enviar eventos. Preparare un ejemplo mas complejo el fin de semana y lo compartire en el blog.
      Saludos

      Eliminar
    3. Muchas gracias por la pronta respuesta, da gusto ver bloggers que mantienen al día sus blogs después de tanto tiempo.

      Eliminar
    4. Hola que tal Oscar, este es uno de los ejemplos sencillos que prepare para tratar de responder a tu pregunta. http://blogti3r.blogspot.com/2013/03/ejemplo-con-viewpager-extendido.html
      Estoy desarrollando una app un poco mas elaborada (escritor de notas) para poder ejemplificar el ViewPager mejor. Cuando la tenga la agregare al blog también.
      Saludos

      Eliminar
    5. Gracias por el ejemplo, estuve trasteando con ViewPager mientras esperaba y logre comprenderlo bastante bien, resultó ser todo más sencillo y organizado de lo que parecía a priori. Muy buen ejemplo, y enhorabuena por el blog, un trabajo magnifico!

      Eliminar
  6. Buenas, he modificado un poco el codigo porque lo que yo quiero es meter relativelayouts en cada fragmento y funciona perfectamente, salvo cuando estoy moviendome en una direccion y vuelvo al fragmento anterior, el error que me da es este: The specified child already has a parent. You must call removeView() on the child's parent first.
    Saludos!

    ResponderEliminar
    Respuestas
    1. Que tal pablo. Que bien que el ejemplo te haya funcionado. Generalmente ese error se presenta cuando inflamos un layout y lo queremos asignar a un grupo. Esto depende mucho de donde estes construllendo tu vista, si a tu vista la estas construyendo con LayoutInflater.inflate(view,group) o algo similar, solo remueve el grupo y cambialo por null eso debe de ayudar. Si prefieres puedes escribirme un mail con un ejemplo de tu codigo para revisarlo o con tu perfil de github para ver el proyecto.
      Saludos y espero te sea de ayuda.

      Eliminar
    2. Gracias por contestar tan rapido, donde puedo encontrar tu email para escribirte un mail?
      Los relativeLayouts me los creo desde código (cada uno tiene 2 ImageButton) y me los creo en el onCreate de mi actividad (bueno en este caso de mi FragmentActivity)
      Lo creo simplemente con RelativeLayout rl = new RelativeLayout(context) luego le añado los botones
      y al finalizar hago:
      adapter.addFragment(new Fragmentos(rl))

      pager.setAdapter(adapter)

      donde adapter es un MyFragmentPagerAdapter
      y pager el viewPager definido en el xml.

      Muchas gracias otra vez!

      Eliminar
    3. Que tal Pablo, mi email lo puedes encontrar en mi perfil de google. Pero te lo dejo aqui abajo para que no tengas dificultad. el metodo onCreateView del fragmento debe de regresar una vista padre (en este caso creo es tu relative layout) y esta vista no debe de estar asociada a ningun grupo ya que sera asociada automaticamente por la actividad. Tal vez sea este el problema, pero si quieres escribeme un email con un ejemplo de tu codigo y lo podemso revisar.
      ti3r.bubblenet@gmail.com

      Eliminar