Bermigrasi dari ViewPager ke ViewPager2

ViewPager2 adalah versi library ViewPager yang telah ditingkatkan, yang menawarkan fungsi yang ditingkatkan dan mengatasi kesulitan umum dalam penggunaan ViewPager. Jika aplikasi Anda sudah menggunakan ViewPager, baca halaman ini untuk mempelajari lebih lanjut cara bermigrasi ke ViewPager2.

Jika Anda ingin menggunakan ViewPager2 di aplikasi dan saat ini tidak menggunakan ViewPager, baca Menggeser antar-fragmen menggunakan ViewPager2 dan Membuat tampilan geser dengan tab menggunakan ViewPager2 untuk informasi selengkapnya.

Manfaat migrasi ke ViewPager2

Alasan utama untuk melakukan migrasi adalah ViewPager2 menerima dukungan pengembangan aktif, sedangkan ViewPager tidak. Namun, ViewPager2 juga menawarkan beberapa keuntungan spesifik lainnya.

Dukungan orientasi vertikal

ViewPager2 mendukung paging vertikal selain paging horizontal tradisional. Anda dapat mengaktifkan paging vertikal untuk elemen ViewPager2 dengan menetapkan atribut android:orientation-nya:

<androidx.viewpager2.widget.ViewPager2
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:orientation="vertical" />

Anda juga dapat menetapkan atribut ini secara terprogram menggunakan metode setOrientation().

Dukungan kanan-ke-kiri

ViewPager2 mendukung penjelajahan halaman kanan-ke-kiri (RTL). Paging RTL diaktifkan secara otomatis jika sesuai berdasarkan lokalitas, tetapi Anda juga dapat mengaktifkan paging RTL secara manual untuk elemen ViewPager2 dengan menetapkan atribut android:layoutDirection-nya:

<androidx.viewpager2.widget.ViewPager2
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:layoutDirection="rtl" />

Anda juga dapat menetapkan atribut ini secara terprogram menggunakan metode setLayoutDirection().

Kumpulan fragmen yang dapat diubah

ViewPager2 mendukung paging melalui kumpulan fragmen yang dapat diubah, yang memanggil notifyDatasetChanged() untuk mengupdate UI saat koleksi yang mendasarinya berubah.

Artinya, aplikasi Anda dapat secara dinamis memodifikasi kumpulan fragmen saat runtime, dan ViewPager2 akan menampilkan koleksi yang dimodifikasi dengan benar.

DiffUtil

ViewPager2 dibuat di RecyclerView, yang berarti memiliki akses ke class utilitas DiffUtil. Hal ini menghasilkan beberapa manfaat, tetapi yang terutama berarti bahwa objek ViewPager2 secara native memanfaatkan animasi perubahan set data dari class RecyclerView.

Memigrasikan aplikasi Anda ke ViewPager2

Ikuti langkah-langkah berikut untuk memperbarui objek ViewPager di aplikasi Anda ke ViewPager2:

Memperbarui file tata letak XML

Pertama, ganti elemen ViewPager dalam file tata letak XML Anda dengan elemen 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" />

Memperbarui class adaptor

Saat menggunakan ViewPager, Anda harus memperluas class adaptor yang menyediakan halaman baru ke objek tersebut. Bergantung pada kasus penggunaan, ViewPager menggunakan tiga class abstrak yang berbeda. ViewPager2 hanya menggunakan dua class abstrak.

Untuk setiap objek ViewPager yang Anda konversi menjadi objek ViewPager2, update class adaptor untuk memperluas class abstrak yang sesuai seperti berikut:

Parameter konstruktor

Class adaptor berbasis fragmen yang mewarisi dari FragmentPagerAdapter atau FragmentStatePagerAdapter selalu menerima satu objek FragmentManager sebagai parameter konstruktor. Saat memperluas FragmentStateAdapter untuk class adaptor ViewPager2, Anda memiliki opsi berikut untuk parameter konstruktor:

Class adaptor berbasis tampilan yang mewarisi langsung dari RecyclerView.Adapter tidak memerlukan parameter konstruktor.

Mengganti metode

Class adaptor juga perlu mengganti metode yang berbeda untuk ViewPager2 dibandingkan untuk ViewPager:

  • Ganti getItemCount(), bukan getCount(). Selain namanya, metode ini tidak berubah.
  • Ganti createFragment(), bukan getItem(), dalam class adaptor berbasis fragmen. Pastikan metode createFragment() baru Anda selalu menyediakan instance fragmen baru setiap kali fungsi dipanggil, bukan menggunakan kembali instance.

Ringkasan

Singkatnya, untuk mengonversi class adaptor ViewPager agar dapat digunakan dengan ViewPager2, Anda harus melakukan perubahan berikut:

  1. Ubah superclass menjadi RecyclerView.Adapter untuk paging melalui tampilan, atau FragmentStateAdapter untuk paging melalui fragmen.
  2. Ubah parameter konstruktor dalam class adaptor berbasis fragmen.
  3. Ganti getItemCount(), bukan getCount().
  4. Ganti createFragment() dan bukan getItem() dalam class adaptor berbasis fragmen.

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;
    }
}

Faktorkan ulang antarmuka TabLayout

ViewPager2 memperkenalkan perubahan pada integrasi TabLayout. Jika saat ini Anda menggunakan ViewPager dengan objek TabLayout untuk menampilkan tab horizontal untuk navigasi, Anda perlu memfaktorkan ulang objek TabLayout untuk integrasi dengan ViewPager2.

TabLayout telah dipisahkan dari ViewPager2 dan sekarang tersedia sebagai bagian dari komponen Material. Artinya, agar dapat menggunakannya, Anda perlu menambahkan dependensi yang sesuai ke file build.gradle:

Groovy

implementation "com.google.android.material:material:1.1.0-beta01"

Kotlin

implementation("com.google.android.material:material:1.1.0-beta01")

Anda juga perlu mengubah lokasi elemen TabLayout dalam hierarki file tata letak XML. Dengan ViewPager, elemen TabLayout dideklarasikan sebagai turunan dari elemen ViewPager; tetapi dengan ViewPager2, elemen TabLayout dideklarasikan langsung di atas elemen ViewPager2, pada tingkat yang sama:

<!-- 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>

Terakhir, Anda harus memperbarui kode yang melampirkan objek TabLayout ke objek ViewPager. Meskipun menggunakan metode setupWithViewPager() sendiri untuk berintegrasi dengan ViewPager, TabLayout memerlukan instance TabLayoutMediator untuk berintegrasi dengan ViewPager2.

Objek TabLayoutMediator juga menangani tugas membuat judul halaman untuk objek TabLayout, yang berarti class adaptor tidak perlu mengganti 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();
    }
    ...
}

Dukung elemen bertingkat yang dapat di-scroll

ViewPager2 tidak mendukung tampilan scroll bertingkat secara native jika tampilan scroll memiliki orientasi yang sama dengan objek ViewPager2 yang memuatnya. Misalnya, scroll tidak akan berfungsi untuk tampilan scroll vertikal di dalam objek ViewPager2 berorientasi vertikal.

Untuk mendukung tampilan scroll di dalam objek ViewPager2 dengan orientasi yang sama, Anda harus memanggil requestDisallowInterceptTouchEvent() pada objek ViewPager2 jika Anda mengharapkan untuk men-scroll elemen bertingkat. Contoh scroll bertingkat ViewPager2 menunjukkan salah satu cara untuk mengatasi masalah ini dengan tata letak wrapper kustom serbaguna.

Referensi lainnya

Untuk mempelajari ViewPager2 lebih lanjut, baca referensi tambahan berikut ini.

Contoh

Video