ViewPager2
es una versión mejorada de la biblioteca ViewPager
que ofrece
Se mejoró la funcionalidad y aborda dificultades comunes con el uso de ViewPager
.
Si tu app ya usa ViewPager
, consulta esta página para obtener más información sobre el tema.
migrando a ViewPager2
.
Si quieres usar ViewPager2
en tu app y actualmente no lo usas
ViewPager
, lee Cómo deslizar entre fragmentos con
ViewPager2 y Cómo crear vistas deslizantes con
pestañas que usan ViewPager2 para más
información.
Beneficios de la migración a ViewPager2
El motivo principal para migrar es que ViewPager2
recibe
para la asistencia de desarrollo y ViewPager
no. Sin embargo, ViewPager2
también ofrece
muchas otras ventajas específicas.
Compatibilidad con orientación vertical
ViewPager2
admite la paginación vertical y la horizontal tradicional.
la paginación. Puedes habilitar la paginación vertical de un elemento ViewPager2
si configuras su
Atributo android:orientation
:
<androidx.viewpager2.widget.ViewPager2
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:orientation="vertical" />
También puedes establecer el atributo de forma programática con el setOrientation(). .
Asistencia de derecha a izquierda
ViewPager2
admite la paginación de derecha a izquierda (RTL). Se habilitó la paginación RTL
automáticamente cuando corresponda según la configuración regional, pero también puedes
Habilita la paginación de derecha a izquierda para un elemento ViewPager2
configurando su
Atributo android:layoutDirection
:
<androidx.viewpager2.widget.ViewPager2
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layoutDirection="rtl" />
También puedes establecer el atributo de forma programática con el setLayoutDirections(); .
Colecciones de fragmentos modificables
ViewPager2
admite la paginación a través de una colección modificable de fragmentos,
llamando
notifyDatasetChanged()
para actualizar la IU cuando cambie la colección subyacente.
Esto significa que tu app puede modificar dinámicamente la colección de fragmentos en
y ViewPager2
mostrará correctamente la colección modificada.
DiffUtil
ViewPager2
se basa en RecyclerView
,
lo que significa que tiene acceso
Servicio DiffUtil
. Esto trae como resultado varios beneficios, pero notablemente significa que
Los objetos ViewPager2
aprovechan de forma nativa las animaciones de cambio de conjunto de datos.
de la clase RecyclerView
.
Cómo migrar tu app a ViewPager2
Sigue estos pasos para actualizar los objetos ViewPager
en tu app a ViewPager2
:
Cómo actualizar los archivos de diseño XML
Primero, reemplaza los elementos ViewPager
de los archivos de diseño XML por
Elementos ViewPager2
:
<!-- A ViewPager element -->
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- A ViewPager2 element -->
<androidx.viewpager2.widget.ViewPager2
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Cómo actualizar las clases de adaptador
Cuando usaste ViewPager
, tuviste que extender la clase de adaptador que
proporcionaron páginas nuevas al objeto. Según el caso de uso, ViewPager
usó
tres clases abstractas diferentes. ViewPager2
solo usa dos clases abstractas.
Por cada objeto ViewPager
que conviertas en un objeto ViewPager2
, haz lo siguiente:
actualiza la clase de adaptador para extender la clase abstracta adecuada de la siguiente manera:
- Cuando
ViewPager
usóPagerAdapter
para desplazarse por las vistas, usaRecyclerView.Adapter
conViewPager2
. - Cuando
ViewPager
usabaFragmentPagerAdapter
para desplazarse por un tamaño pequeño, cantidad fija de fragmentos, usaFragmentStateAdapter
conViewPager2
. - Cuando
ViewPager
usabaFragmentStatePagerAdapter
para desplazarse por una número grande o desconocido de fragmentos, usaFragmentStateAdapter
conViewPager2
Parámetros de constructor
Las clases de adaptador basadas en fragmentos que heredan de FragmentPagerAdapter
o
FragmentStatePagerAdapter
siempre acepta un único objeto FragmentManager
.
como parámetro de constructor. Cuando extiendes FragmentStateAdapter
por un
ViewPager2
, tienes las siguientes opciones para el constructor
parámetros en su lugar:
- El objeto
FragmentActivity
o el objetoFragment
en el queViewPager2
. Por lo general, esta es la mejor opción. - Un objeto
FragmentManager
y un objetoLifecycle
.
Las clases de adaptador basadas en vistas que se heredan directamente de RecyclerView.Adapter
do
no requieren un parámetro de constructor.
Anular métodos
Las clases de adaptador también deben anular métodos diferentes para ViewPager2
.
que en ViewPager
:
- En lugar de
getCount()
, anulagetItemCount()
. Aparte del nombre, este método no se modificó. - En lugar de
getItem()
, anulacreateFragment()
en objetos de adaptador de alimentación. Asegúrate de que tu nuevo métodocreateFragment()
siempre proporciona una nueva instancia de fragmento cada vez que se llama a la función, en lugar de volver a usar instancias.
Resumen
En resumen, si deseas convertir una clase de adaptador ViewPager
para usarla con ViewPager2
, haz lo siguiente:
debes realizar los siguientes cambios:
- Cambia la superclase a
RecyclerView.Adapter
para paginar las vistas.FragmentStateAdapter
para paginar fragmentos - Cambia los parámetros del constructor en clases de adaptador basadas en fragmentos.
- Anula
getItemCount()
en lugar degetCount()
. - Anula
createFragment()
en lugar degetItem()
en el adaptador basado en fragmentos .
Kotlin
// A simple ViewPager adapter class for paging through fragments class ScreenSlidePagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) { override fun getCount(): Int = NUM_PAGES override fun getItem(position: Int): Fragment = ScreenSlidePageFragment() } // An equivalent ViewPager2 adapter class class ScreenSlidePagerAdapter(fa: FragmentActivity) : FragmentStateAdapter(fa) { override fun getItemCount(): Int = NUM_PAGES override fun createFragment(position: Int): Fragment = ScreenSlidePageFragment() }
Java
// A simple ViewPager adapter class for paging through fragments public class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter { public ScreenSlidePagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return new ScreenSlidePageFragment(); } @Override public int getCount() { return NUM_PAGES; } } // An equivalent ViewPager2 adapter class private class ScreenSlidePagerAdapter extends FragmentStateAdapter { public ScreenSlidePagerAdapter(FragmentActivity fa) { super(fa); } @Override public Fragment createFragment(int position) { return new ScreenSlidePageFragment(); } @Override public int getItemCount() { return NUM_PAGES; } }
Cómo refactorizar interfaces de TabLayout
ViewPager2
trae cambios en la integración de TabLayout
. Si
ahora usas un ViewPager
con un objeto TabLayout
para que se muestre de forma horizontal
pestañas para la navegación, debes refactorizar el objeto TabLayout
de
integración con ViewPager2
.
TabLayout
se desacopló de ViewPager2
y ahora está disponible como parte de
Componentes de Material. Esto significa que, para usarlo, debes agregar
la dependencia adecuada a tu archivo build.gradle
:
Groovy
implementation "com.google.android.material:material:1.1.0-beta01"
Kotlin
implementation("com.google.android.material:material:1.1.0-beta01")
También debes cambiar la ubicación del elemento TabLayout
en la jerarquía de
tu archivo de diseño XML. Con ViewPager
, el elemento TabLayout
se declara como un
elemento secundario del elemento ViewPager
; pero con ViewPager2
, el elemento TabLayout
se declara directamente sobre el elemento ViewPager2
, en el mismo nivel:
<!-- A ViewPager element with a TabLayout -->
<androidx.viewpager.widget.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</androidx.viewpager.widget.ViewPager>
<!-- A ViewPager2 element with a TabLayout -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
Por último, debes actualizar el código que adjunta el objeto TabLayout
al
ViewPager
. Si bien TabLayout
usa su propio setupWithViewPager()
de integración con ViewPager
, se requiere un elemento TabLayoutMediator
para integrarla con ViewPager2
.
El objeto TabLayoutMediator
también controla la tarea de generar títulos de página.
para el objeto TabLayout
, lo que significa que la clase de adaptador no necesita
anular getPageTitle()
:
Kotlin
// Integrating TabLayout with ViewPager class CollectionDemoFragment : Fragment() { ... override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val tabLayout = view.findViewById(R.id.tab_layout) tabLayout.setupWithViewPager(viewPager) } ... } class DemoCollectionPagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) { override fun getCount(): Int = 4 override fun getPageTitle(position: Int): CharSequence { return "OBJECT ${(position + 1)}" } ... } // Integrating TabLayout with ViewPager2 class CollectionDemoFragment : Fragment() { ... override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val tabLayout = view.findViewById(R.id.tab_layout) TabLayoutMediator(tabLayout, viewPager) { tab, position -> tab.text = "OBJECT ${(position + 1)}" }.attach() } ... }
Java
// Integrating TabLayout with ViewPager public class CollectionDemoFragment extends Fragment { ... @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { TabLayout tabLayout = view.findViewById(R.id.tab_layout); tabLayout.setupWithViewPager(viewPager); } ... } public class DemoCollectionPagerAdapter extends FragmentStatePagerAdapter { ... @Override public int getCount() { return 4; } @Override public CharSequence getPageTitle(int position) { return "OBJECT " + (position + 1); } ... } // Integrating TabLayout with ViewPager2 public class CollectionDemoFragment : Fragment() { ... @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { TabLayout tabLayout = view.findViewById(R.id.tab_layout); new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> tab.setText("OBJECT " + (position + 1)) ).attach(); } ... }
Cómo admitir elementos desplazables anidados
ViewPager2
no admite vistas de desplazamiento anidadas de forma nativa en los casos en que el elemento
tiene la misma orientación que el objeto ViewPager2
que contiene
que la modifica. Por ejemplo, el desplazamiento no funcionaría en una vista de desplazamiento vertical dentro de una
Objeto ViewPager2
orientado verticalmente
Para admitir una vista de desplazamiento dentro de un objeto ViewPager2
con la misma orientación,
debes llamar
requestDisallowInterceptTouchEvent()
en el objeto ViewPager2
cuando
esperas desplazar el elemento anidado en su lugar. El desplazamiento anidado de ViewPager2
demuestra una forma de resolver este problema con una solución
diseño de wrapper personalizado.
Recursos adicionales
Para obtener más información sobre ViewPager2
, consulta los siguientes recursos adicionales.
Ejemplos
- Ejemplos de ViewPager2 en GitHub
Videos
- Pasar la página: cómo migrar a ViewPager2 (Android Dev Summit 2019)