Esegui la migrazione da ViewPager a ViewPager2

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:

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 o Fragment in cui L'oggetto ViewPager2 risiede. Nella maggior parte dei casi, questa è l'opzione migliore.
  • Un oggetto FragmentManager e un oggetto Lifecycle.

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(), sostituisci getItemCount(). Oltre al nome, questo metodo è rimasto invariato.
  • Al posto di getItem(), sostituisci createFragment() in base ai frammenti classi di adattatori. Assicurati che il nuovo metodo createFragment() sia sempre fornisce una nuova istanza di frammento ogni volta che viene chiamata la funzione anziché delle istanze VM.
di Gemini Advanced.

Riepilogo

In sintesi, per convertire una classe adattatore ViewPager da utilizzare con ViewPager2, devi apportare le seguenti modifiche:

  1. Cambia la superclasse in RecyclerView.Adapter per navigare nelle visualizzazioni oppure FragmentStateAdapter per il paging dei frammenti.
  2. Modificare i parametri del costruttore nelle classi degli adattatori basati su frammenti.
  3. Esegui l'override di getItemCount() anziché getCount().
  4. 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

Video