Bermigrasi dari ViewPager ke ViewPager2

ViewPager2 adalah versi yang ditingkatkan dari library ViewPager yang menawarkan fungsi yang ditingkatkan dan menangani 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 Bergeser antar-fragmen menggunakan ViewPager2 dan Membuat tampilan geser dengan tab menggunakan ViewPager2 untuk informasi selengkapnya.

Manfaat migrasi ke ViewPager2

Alasan utama untuk bermigrasi adalah karena ViewPager2 menerima dukungan pengembangan aktif, sedangkan ViewPager tidak. Namun, ViewPager2 juga menawarkan beberapa keunggulan 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, memanggil notifyDatasetChanged() untuk mengupdate UI saat kumpulan yang mendasarinya berubah.

Artinya, aplikasi Anda dapat mengubah koleksi fragmen secara dinamis saat runtime, dan ViewPager2 akan menampilkan koleksi yang diubah dengan benar.

DiffUtil

ViewPager2 dibuat di RecyclerView, yang berarti memiliki akses ke class utilitas DiffUtil. Hal ini memberikan beberapa manfaat, tetapi yang paling penting adalah 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. 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, perbarui class adaptor untuk memperluas class abstrak yang sesuai sebagai berikut:

Parameter konstruktor

Class adaptor berbasis fragmen yang diwarisi 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 diwarisi langsung dari RecyclerView.Adapter tidak memerlukan parameter konstruktor.

Mengganti metode

Class adaptor Anda juga perlu mengganti metode yang berbeda untuk ViewPager2 daripada yang dilakukan untuk ViewPager:

  • Ganti getItemCount(), bukan getCount(). Selain nama, metode ini tidak berubah.
  • Sebagai ganti getItem(), ganti createFragment() di 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(), bukan getItem() di 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 merefaktorisasi objek TabLayout untuk integrasi dengan ViewPager2.

TabLayout telah dipisahkan dari ViewPager2 dan kini tersedia sebagai bagian dari Komponen material. Artinya, untuk 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 tepat 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 mengupdate kode yang melampirkan objek TabLayout ke objek ViewPager. Meskipun TabLayout menggunakan metode setupWithViewPager() -nya sendiri untuk berintegrasi dengan ViewPager, memerlukan instance TabLayoutMediator untuk berintegrasi dengan ViewPager2.

Objek TabLayoutMediator juga menangani tugas pembuatan 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 berisi tampilan tersebut. Misalnya, scroll tidak akan berfungsi untuk tampilan scroll vertikal di dalam objek ViewPager2 yang berorientasi vertikal.

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

Referensi lainnya

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

Video