ViewPager'den ViewPager2'ye geçiş

ViewPager2, ViewPager kitaplığının gelişmiş bir sürümüdür. Bu sürüm, gelişmiş işlevler sunar ve ViewPager kullanımıyla ilgili yaygın sorunları giderir. Uygulamanızda ViewPager kullanılıyorsa ViewPager2 hizmetine geçiş hakkında daha fazla bilgi edinmek için bu sayfayı okuyun.

Uygulamanızda ViewPager2 kullanmak istiyorsanız ve şu anda ViewPager kullanmıyorsanız daha fazla bilgi için ViewPager2 kullanarak parçalar arasında kaydırma ve ViewPager2 kullanarak sekmelerle kaydırma görünümleri oluşturma başlıklı makaleleri okuyun.

ViewPager2'ye geçmenin avantajları

Geçiş yapmanın temel nedeni, ViewPager2 için etkin geliştirme desteği sunulurken ViewPager için sunulmamasıdır. Ancak ViewPager2, başka avantajlar da sunar.

Dikey yön desteği

ViewPager2, geleneksel yatay sayfalama özelliğinin yanı sıra dikey sayfalama özelliğini de destekler. android:orientation özelliğini ayarlayarak bir ViewPager2 öğesi için dikey sayfa gezginini etkinleştirebilirsiniz:

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

Bu özelliği, setOrientation() yöntemini kullanarak programatik olarak da ayarlayabilirsiniz.

Sağdan sola desteği

ViewPager2, sağdan sola (RTL) sayfa düzenini destekler. Sağdan sola sayfa gezgini, yerel ayara göre uygun olan yerlerde otomatik olarak etkinleştirilir ancak android:layoutDirection özelliğini ayarlayarak ViewPager2 öğesi için sağdan sola sayfa gezginini manuel olarak da etkinleştirebilirsiniz:

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

Bu özelliği, setLayoutDirection() yöntemini kullanarak programatik olarak da ayarlayabilirsiniz.

Değiştirilebilir parça koleksiyonları

ViewPager2, değiştirilebilir bir parça koleksiyonunda sayfa gezginini destekler ve temel koleksiyon değiştiğinde kullanıcı arayüzünü güncellemek için notifyDatasetChanged() yöntemini çağırır.

Bu, uygulamanızın çalışma zamanında parça koleksiyonunu dinamik olarak değiştirebileceği ve ViewPager2 öğesinin değiştirilen koleksiyonu doğru şekilde göstereceği anlamına gelir.

DiffUtil

ViewPager2, RecyclerView üzerine kuruludur. Bu nedenle DiffUtil yardımcı program sınıfına erişebilir. Bu durum çeşitli avantajlar sağlar. En önemlisi, ViewPager2 nesnelerinin RecyclerView sınıfındaki veri kümesi değişikliği animasyonlarından doğal olarak yararlanmasıdır.

Uygulamanızı ViewPager2'ye taşıma

Uygulamanızdaki ViewPager nesnelerini ViewPager2 olarak güncellemek için aşağıdaki adımları uygulayın:

XML düzen dosyalarını güncelleme

Öncelikle XML düzen dosyalarınızdaki ViewPager öğelerini ViewPager2 öğeleriyle değiştirin:

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

Bağdaştırıcı sınıflarını güncelleme

ViewPager kullanırken nesneye yeni sayfalar sağlayan bağdaştırıcı sınıfını genişletmeniz gerekiyordu. Kullanım alanına bağlı olarak ViewPager, üç farklı soyut sınıf kullandı. ViewPager2 yalnızca iki soyut sınıf kullanır.

ViewPager2 nesnesine dönüştürdüğünüz her ViewPager nesnesi için adaptör sınıfını, uygun soyut sınıfı aşağıdaki gibi genişletecek şekilde güncelleyin:

Oluşturucu parametreleri

FragmentPagerAdapter veya FragmentStatePagerAdapter sınıfından devralınan parça tabanlı bağdaştırıcı sınıfları, her zaman kurucu parametresi olarak tek bir FragmentManager nesnesi kabul eder. ViewPager2 bağdaştırıcı sınıfı için FragmentStateAdapter sınıfını genişlettiğinizde, yapıcı parametreleri için aşağıdaki seçenekleri kullanabilirsiniz:

  • ViewPager2 nesnesinin bulunduğu FragmentActivity nesnesi veya Fragment nesnesi. Çoğu durumda bu daha iyi bir seçenektir.
  • Bir FragmentManager nesnesi ve bir Lifecycle nesnesi.

Doğrudan RecyclerView.Adapter sınıfından devralınan görünüme dayalı bağdaştırıcı sınıfları için kurucu parametresi gerekmez.

Geçersiz kılma yöntemleri

Bağdaştırıcı sınıflarınızın, ViewPager2 için ViewPager'dekinden farklı yöntemleri geçersiz kılması da gerekir:

  • getCount() yerine getItemCount() değerini geçersiz kılın. Adı dışında bu yöntemde herhangi bir değişiklik yapılmadı.
  • getItem() yerine, parça tabanlı bağdaştırıcı sınıflarında createFragment() yöntemini geçersiz kılın. Yeni createFragment() yönteminizin, örnekleri yeniden kullanmak yerine işlev her çağrıldığında her zaman yeni bir parça örneği sağladığından emin olun.

Özet

Özetle, bir ViewPager bağdaştırıcı sınıfını ViewPager2 ile kullanılacak şekilde dönüştürmek için aşağıdaki değişiklikleri yapmanız gerekir:

  1. Görünümler arasında sayfa gezgini kullanmak için üst sınıfı RecyclerView.Adapter, parçalar arasında sayfa gezgini kullanmak için FragmentStateAdapter olarak değiştirin.
  2. Parça tabanlı bağdaştırıcı sınıflarındaki kurucu parametrelerini değiştirin.
  3. getCount() yerine getItemCount() değerini geçersiz kılın.
  4. Parça tabanlı bağdaştırıcı sınıflarında getItem() yerine createFragment() yöntemini geçersiz kılın.

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

TabLayout arayüzlerini yeniden düzenleme

ViewPager2, TabLayout entegrasyonunda değişiklikler yapıyor. Şu anda gezinme için yatay sekmeler görüntülemek üzere TabLayout nesnesiyle birlikte ViewPager kullanıyorsanız ViewPager2 ile entegrasyon için TabLayout nesnesini yeniden düzenlemeniz gerekir.

TabLayout, ViewPager2'den ayrıldı ve artık Materyal bileşenleri kapsamında kullanılabilir. Bu nedenle, kitaplığı kullanmak için build.gradle dosyanıza uygun bağımlılığı eklemeniz gerekir:

Modern

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

Kotlin

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

Ayrıca, XML düzen dosyanızın hiyerarşisinde TabLayout öğesinin konumunu da değiştirmeniz gerekir. ViewPager ile TabLayout öğesi, ViewPager öğesinin alt öğesi olarak tanımlanır. ViewPager2 ile ise TabLayout öğesi, doğrudan ViewPager2 öğesinin üzerinde, aynı düzeyde tanımlanır:

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

Son olarak, TabLayout nesnesini ViewPager nesnesine ekleyen kodu güncellemeniz gerekir. TabLayout, ViewPager ile entegrasyon için kendi setupWithViewPager() yöntemini kullanırken ViewPager2 ile entegrasyon için bir TabLayoutMediator örneği gerektirir.

TabLayoutMediator nesnesi, TabLayout nesnesi için sayfa başlıkları oluşturma görevini de üstlenir. Bu, adaptör sınıfının getPageTitle() yöntemini geçersiz kılmasına gerek olmadığı anlamına gelir:

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();
    }
    ...
}

İç içe yerleştirilmiş kaydırılabilir öğeleri destekleme

ViewPager2, kaydırma görünümünün kendisini içeren ViewPager2 nesnesiyle aynı yöne sahip olduğu durumlarda iç içe yerleştirilmiş kaydırma görünümlerini yerel olarak desteklemez. Örneğin, dikey olarak yönlendirilmiş bir ViewPager2 nesnesinin içindeki dikey kaydırma görünümünde kaydırma işlemi çalışmaz.

Aynı yöne sahip bir ViewPager2 nesnesinin içindeki kaydırma görünümünü desteklemek için iç içe yerleştirilmiş öğeyi kaydırmayı beklediğinizde ViewPager2 nesnesinde requestDisallowInterceptTouchEvent() yöntemini çağırmanız gerekir. ViewPager2 iç içe yerleştirilmiş kaydırma örneği, çok yönlü bir özel sarmalayıcı düzeni ile bu sorunu çözmenin bir yolunu gösterir.

Ek kaynaklar

ViewPager2 hakkında daha fazla bilgi edinmek için aşağıdaki ek kaynaklara göz atın.

Videolar