ViewPager2
è una versione migliorata della libreria ViewPager
che offre
funzionalità avanzate e risolve le difficoltà comuni legate all'utilizzo di ViewPager
.
Se la tua app utilizza già ViewPager
, leggi questa pagina per scoprire di più su
migrazione a ViewPager2
.
Se vuoi usare ViewPager2
nella tua app ma non la stai usando al momento
ViewPager
, leggi Scorrere tra i frammenti utilizzando
ViewPager2 e Crea visualizzazioni scorrimento con
schede utilizzando ViewPager2 per
informazioni.
Vantaggi della migrazione a ViewPager2
Il motivo principale della migrazione è che l'app ViewPager2
è sempre attiva
il supporto per lo sviluppo, mentre ViewPager
non lo è. Tuttavia, ViewPager2
offre anche
diversi altri vantaggi specifici.
Supporto dell'orientamento verticale
ViewPager2
supporta il paging verticale oltre al formato orizzontale tradizionale
il paging. Puoi attivare il paging verticale per un elemento ViewPager2
impostando il relativo
Attributo android:orientation
:
<androidx.viewpager2.widget.ViewPager2
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:orientation="vertical" />
Puoi anche impostare questo attributo in modo programmatico utilizzando il metodo setOrientation() .
Supporto da destra a sinistra
ViewPager2
supporta il paging da destra a sinistra (RTL). Il paging RTL è abilitato
automaticamente ove appropriato in base alle impostazioni internazionali, ma puoi anche
abilita il paging RTL per un elemento ViewPager2
impostandone il
Attributo android:layoutDirection
:
<androidx.viewpager2.widget.ViewPager2
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layoutDirection="rtl" />
Puoi anche impostare questo attributo in modo programmatico utilizzando il metodo setLayoutDirection() .
Raccolte di frammenti modificabili
ViewPager2
supporta il paging tramite una raccolta modificabile di frammenti,
chiamata
notifyDatasetChanged()
per aggiornare l'UI quando la raccolta sottostante cambia.
Ciò significa che la tua app può modificare dinamicamente la raccolta dei frammenti all'indirizzo
runtime: ViewPager2
mostrerà correttamente la raccolta modificata.
DiffUtil
ViewPager2
è basato su RecyclerView
,
il che significa che ha accesso
Utility DiffUtil
. Ciò si traduce in numerosi vantaggi, ma in particolare
ViewPager2
oggetti sfruttano in modo nativo le animazioni di modifica del set di dati
del corso RecyclerView
.
Esegui la migrazione dell'app a ViewPager2
Segui questi passaggi per aggiornare ViewPager
di oggetti nell'app a ViewPager2
:
Aggiorna i file di layout XML
Per prima cosa, sostituisci gli elementi ViewPager
nei file di layout XML con
Elementi 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" />
Aggiorna classi adattatori
Quando hai usato ViewPager
, hai dovuto estendere la classe dell'adattatore che
ha fornito nuove pagine all'oggetto. A seconda del caso d'uso, è stato usato ViewPager
tre diverse classi astratte. ViewPager2
utilizza solo due classi astratte.
Per ogni oggetto ViewPager
che stai convertendo in un oggetto ViewPager2
,
aggiorna la classe dell'adattatore per estendere la classe astratta appropriata come segue:
- Quando
ViewPager
ha utilizzatoPagerAdapter
per le visualizzazioni di pagina, usaRecyclerView.Adapter
conViewPager2
. - Quando
ViewPager
ha usatoFragmentPagerAdapter
per scorrere un piccolo testo, numero fisso di frammenti, utilizzaFragmentStateAdapter
conViewPager2
. - Quando
ViewPager
ha usatoFragmentStatePagerAdapter
per scorrere una pagina numero elevato o sconosciuto di frammenti, utilizzaFragmentStateAdapter
conViewPager2
.
Parametri costruttore
Classi di adattatori basati su frammenti che ereditano da FragmentPagerAdapter
o
FragmentStatePagerAdapter
accetta sempre un singolo oggetto FragmentManager
come parametro del costruttore. Quando estendi FragmentStateAdapter
per una
Classe adattatore ViewPager2
, hai le seguenti opzioni per il costruttore
:
- L'oggetto
FragmentActivity
oFragment
in cui L'oggettoViewPager2
risiede. Nella maggior parte dei casi, questa è l'opzione migliore. - Un oggetto
FragmentManager
e un oggettoLifecycle
.
Le classi di adattatori basati sulla visualizzazione ereditano direttamente da RecyclerView.Adapter
non richiedono un parametro costruttore.
Metodi di override
Le classi di adattatori devono anche sostituire metodi diversi per ViewPager2
rispetto a ViewPager
:
- Al posto di
getCount()
, sostituiscigetItemCount()
. Oltre al nome, questo metodo è rimasto invariato. - Al posto di
getItem()
, sostituiscicreateFragment()
in base ai frammenti classi di adattatori. Assicurati che il nuovo metodocreateFragment()
sia sempre fornisce una nuova istanza di frammento ogni volta che viene chiamata la funzione anziché delle istanze VM.
Riepilogo
In sintesi, per convertire una classe adattatore ViewPager
da utilizzare con ViewPager2
,
devi apportare le seguenti modifiche:
- Cambia la superclasse in
RecyclerView.Adapter
per navigare nelle visualizzazioni oppureFragmentStateAdapter
per il paging dei frammenti. - Modificare i parametri del costruttore nelle classi degli adattatori basati su frammenti.
- Esegui l'override di
getItemCount()
anzichégetCount()
. - Esegui l'override di
createFragment()
anzichégetItem()
nell'adattatore basato su frammenti .
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; } }
Esegui il refactoring delle interfacce TabLayout
ViewPager2
introduce modifiche all'integrazione di TabLayout
. Se
attualmente utilizza ViewPager
con un oggetto TabLayout
per visualizzare in orizzontale
per la navigazione, devi eseguire il refactoring dell'oggetto TabLayout
integrazione con ViewPager2
.
TabLayout
è stato disaccoppiato da ViewPager2
ed è ora disponibile come parte di
Componenti dei materiali. Ciò significa che per utilizzarla, devi aggiungere
la dipendenza appropriata per il tuo file build.gradle
:
Alla moda
implementation "com.google.android.material:material:1.1.0-beta01"
Kotlin
implementation("com.google.android.material:material:1.1.0-beta01")
Devi anche modificare la posizione dell'elemento TabLayout
nella gerarchia di
del tuo file di layout XML. Con ViewPager
, l'elemento TabLayout
viene dichiarato come
figlio dell'elemento ViewPager
; ma con ViewPager2
, l'elemento TabLayout
viene dichiarato direttamente sopra l'elemento ViewPager2
, allo stesso livello:
<!-- 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>
Infine, devi aggiornare il codice che collega l'oggetto TabLayout
alla
Oggetto ViewPager
. TabLayout
usa il proprio setupWithViewPager()
per l'integrazione con ViewPager
, richiede un TabLayoutMediator
per l'integrazione con ViewPager2
.
L'oggetto TabLayoutMediator
gestisce anche l'attività di generazione dei titoli delle pagine
per l'oggetto TabLayout
, il che significa che la classe dell'adattatore non deve
sostituisci 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(); } ... }
Supporta elementi scorrevoli nidificati
ViewPager2
non supporta in modo nativo le visualizzazioni a scorrimento nidificate nei casi in cui
visualizzazione scorrimento ha lo stesso orientamento dell'oggetto ViewPager2
che contiene
li annotino. Ad esempio, lo scorrimento non funziona per una visualizzazione con scorrimento verticale all'interno di una
oggetto ViewPager2
con orientamento verticale.
Per supportare una visualizzazione a scorrimento all'interno di un oggetto ViewPager2
con lo stesso orientamento:
devi chiamare
requestDisallowInterceptTouchEvent()
sull'oggetto ViewPager2
quando
ma prevedi di scorrere
l'elemento nidificato. Lo scorrimento nidificato di ViewPager2
esempio mostra un modo per risolvere questo problema con un'applicazione
layout del wrapper personalizzato.
Risorse aggiuntive
Per scoprire di più su ViewPager2
, consulta le seguenti risorse aggiuntive.
Campioni
- Esempi di ViewPager2 su GitHub
Video
- Già pagina: migrazione a ViewPager2 (Android Dev Summit '19)