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
ViewPagerha utilizzatoPagerAdapterper le visualizzazioni di pagina, usaRecyclerView.AdapterconViewPager2. - Quando
ViewPagerha usatoFragmentPagerAdapterper scorrere un piccolo testo, numero fisso di frammenti, utilizzaFragmentStateAdapterconViewPager2. - Quando
ViewPagerha usatoFragmentStatePagerAdapterper scorrere una pagina numero elevato o sconosciuto di frammenti, utilizzaFragmentStateAdapterconViewPager2.
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
FragmentActivityoFragmentin cui L'oggettoViewPager2risiede. Nella maggior parte dei casi, questa è l'opzione migliore. - Un oggetto
FragmentManagere 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.Adapterper navigare nelle visualizzazioni oppureFragmentStateAdapterper 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)