ViewPager2
Explicación del concepto de ViewPager2
DEFINICIÓN
Hereda de ViewGroup.
Muestra objetos de Views o Fragments en formato deslizable, como si de diapositivas se tratara.
RecyclerView VS ViewPager2
La realidad es que ViewPager2 es muy parecido a un RecyclerView y, de hecho, puede utilizar el Adapter y ViewHolder de un RecyclerView. Sin embargo, tiene una serie de diferencias:

RecyclerView
Las ventajas que tiene RecyclerView son:
Permite utilizar GridLayoutManager.
Permite ver varias "Páginas" por VIsta.
No frena el Scroll en cada "página".
Con
LinearSnapHelperse puede hacer que el scroll siempre frene en una "página" y no entre medio.
ViewPager2
Las ventajas que tiene ViewPager2 son:
Con
TabLayoutMediatorpermite configurar unTabLayoutque funcione en conjunto con elViewPager2.Con
PageTransformerse pueden desarrollar nuevas transiciones entre páginas.con
FragmentStateAdaptorpermite que se utilicen Fragments en vez de ViewHolders.con
FakeDragse puede crear una zona de la pantalla que controle el scroll.
Elementos comunes
ViewPager2 coje muchos elementos de RecyclerView como son:
El uso de
ViewHolderpara controlar lo que se muestra en cada una de las "páginas".El uso de
RecyclerViewAdaptor(ViewHolder)cuando no se utilizan Fragments.El uso de
LinearLayoutManager(no se define explícitamente pues es obligatorio).La posibilidad de mostrar una "página" por Vista.
El uso de
PagerSnapHelperque permite aRecyclerViewpaginar las vistas de la misma manera que lo hace ViewPager2 y que se pare el scroll en cada una de las "páginas".
CONFIGURACIÓN
Una vez visto lo anterior, sabemos que puede tener dos usos:
Uso de
ViewPager2con ViewHolder.Uso de
ViewPager2con Fragments.
Uso de ViewPager2 con ViewHolder
ViewPager2 con ViewHolderEste caso de uso es muy parecido al funcionamiento de un RecyclerView. Necesitamos desarrollar los siguientes archivos:
MainActivity.ktactivity_main.xmlpage_model.xmlCharacterModel.ktCharacterProvider.ktPagerAdapter.ktPagerViewHolder.kt
El ejemplo va a ser el mismo que con el RecyclerView pero ligeramente más desarrollado.
Vamos a comenzar:
Crear la Activity y el Layout
Lo primero que debemos hacer es crear una Activity y en el Layout definir una vista ViewPager2:
Por ahora con el archivo MainActivity.kt no vamos a hacer nada.
Definir el modelo de datos
Los datos que se asignan a las entradas de un RecyclerView pueden provenir de muchos sitios.
Pueden encontrarse hardcodeados en la Activity, cosa que no es adecuada.
Pueden encontrarse en una data class.
Pueden obtenerse de una API.
Pueden obtenerse de una consulta a una base de datos.
En este caso, se van a obtener de una data class ya que el resto de opciones son bastante más complejas y requieren de la preexistencia de una API o de una Base de Datos.
Para el modelo de datos, por tanto, vamos a crear una Data Class llamada CharacterModel.kt que va a definir el modelo de personaje y una clase con un método público (companion object en Kotlin) que hará de Proveedor, en este caso CharacterProvider.kt
AVISO
En este ejemplo, al contrario que en el de RecyclerView, no vamos a utilizar imagenes de Internet.
Además, se van a utilizar resources de la App en vez de todo Strings Hardcodeadas.
Definir el Layout de cada página
El Layout de cada página se define de la misma manera que en un RecyclerView con un archivo de Layout en xml llamado page_model.xml.
Y queda de esta manera tan atractiva:

Definir el Adapter y el ViewHolder
Esto se ha visto en profundidad en la entrada de RecyclerView por lo que aquí no vamos a parar tanto:
Función bind(CharacterModel)
En este caso quería explicar esta función por que es importante a la hora de implementar la lógica de este formato.
Si recordamos en el CharacterModel, teníamos:
Como vemos, la descripción a pesar de ser (físicamente) una String, es de tipo Int. Esto se debe a que al rescatarla del CharacterProvider, se está llamando a un recurso string almacenado en el archivo strings.xml esta llamada devuelve un identificador entero de ese recurso. Es por eso que su tipo es Int a pesar de ser un texto.
Lo mismo ocurre con el background, gender y photo. En este caso, podemos ver como su rescate del CharacterProvider sigue otra lógica que la de la description. Esto se debe a que la description es un recurso string mientras que el resto son recursos drawables.
PRECAUCIÓN
Como vemos, los colores almacenados en colors.xml son drawables.
Existe una función ContextCompat.getColor pero requiere de un drawable no de un Int. Es por eso que en este caso no se puede utilizar.
Por último, la parte que hace referencia a los botones es fundamental para que en la primera página no se muestra el botón de atrás y en la última se muestre el botón de finalizar en vez de el de siguiente.
Su comportamiento lo desarrollaremos posteriormente.
Ejecutar el Pager en la Activity
Una vez tenemos todo lo anterior hecho, podemos ir a MainActivity.kt y crear la función setUpPager().
Esto ya funciona, sin embargo, cada página tiene unos botones que debemos configurar:
Dar funcionalidad a los botones
Lo primero que vamos a hacer es crear una interface que llamaremos OnItemSelected y nos permitirá transmitir esta información entre el Adapter, el ViewHolder y la Activity.
Ahora debemos implementar estas funciones:
PagerViewHolder:
En el ViewHolder introducimos como parámetro la interface y dentro de la función bind definimos que cuando se clique sobre uno de los dos botones se hará una llamada la función que para cada uno corresponde dentro de la interface:
Como además, vamos a utilizar los botones para navegar, necesitamos saber cual es la posición del adaptador, o lo que es lo mismo, la página en la que nos encontramos. Es por eso que en las llamadas a las funciones de la interface se pasa por parámetro la absoluteAdapterPosition.
PagerAdapter
Al PagerAdapter también le debemos mandar por parámetro la interface ya que en la función miembro onCreateViewHolder, le tenemos que pasar por parámetro dicha interface.
MainActivity
En el MainActivity indicamos que la clase extiende de OnItemSelected y nos pedirá que implementemos los miembros. De esta manera podremos darle lógica al comportamiento de los botones:
Finalmente, el resultado es bastante gratificante:

Transformer
Si no nos gusta que la animación sea la clásica de diapositiva, podemos crear nuestras propias animaciones y añadirlas a nuestro ViewPager2.
En este ejemplo sólo vamos a utilizar los dos ejemplos de Google:
Esto lo aplicamos en la función setUpPager() de la MainActivity:
Ejemplo DepthPageTransformer

Ejemplo ZoomOutPageTransformer

Uso de ViewPager2 con Fragments
ViewPager2 con FragmentsEl caso de los Fragments es un poco más tedioso por que implica un poco más de configuración, sin embargo, es más versátil.
Para este segundo ejemplo vamos a necesitar desarrollar los siguientes archivos:
MainActivity.ktactivity_main.xmlPageFragment.ktfragment_page.xmlCharacterModel.ktCharacterProvider.ktMyFragmentStateAdapter.kt
El ejemplo será igual que el anterior pero sin botones de siguiente y previo ya que requieren un poco más de conocimiento sobre Fragments.
A cambio, se utilizará este proyecto para añadirle Tabs.
Empecemos:
Crear la Activity y el Layout
Lo primero que debemos hacer es crear una Activity y en el Layout definir una vista ViewPager2:
Por ahora con el archivo MainActivity.kt no vamos a hacer nada.
El CharacterProvider.kt es exactamente el mismo que en el ejemplo anterior.
Sin embargo la CharacterModel.kt que es la data class que ofrece el modelo, es muy importante que implemente la Interface Parcelable.
Una vez la implementemos, nos pedirá que implementemos sus miembros. En este caso, los miembros que implementa Android suelen ser siempre iguales y no hay que hacer ninguna modificación (de manera general):
Crear el Fragment que contendrá la información
Este Fragment será el que indique el Layout de cada una de las páginas:
El archivo PageFragment.kt será el que actue como ViewHolder. Lo configuraremos en pasos posteriores.
Definir el FragmentStateAdapter
A continuación procederemos a definir el Adapter. Este Adapter extenderá de FragmentStateAdapter(fragment) y por ello tendrá que implementar dos miembros:
getItemCount()createFragment()
Como necesitamos saber cuantos Ítems tenemos, tendremos que pasarle al Adapter una lista por parámetro.
Ahora que tenemos todo lo necesario podemos implementar los miembros:
getItemCount()
getItemCount()createFragment()
Esta función simplemente llamará al newInstance del Fragment con los parámetros que necesita para bindear las vistas, luego lo veremos:
Y así nos queda un Adapter de la siguiente manera:
Implementar la lógica del Fragment
El Fragment recibirá por parámetro la posición de la página actual y el objeto del tipo CharacterModel que tiene que bindear.
En el Fragment, lo único que afecta a la Lógica de la App es la parte de OnViewCreated que es el momento en el que Bindeamos las vistas con la información del modelo.
Bindear el adapter con el ViewPager2
Lo único que nos queda es relacionar nuestro adapter con el ViewPager2 en la MainActivity y asignarle un Transformer como hemos visto arriba:
Como resultado tenemos la siguiente grabación:

Last updated
