ViewPager से ViewPager2 पर माइग्रेट करें

ViewPager2, ViewPager लाइब्रेरी का बेहतर वर्शन है. इसमें बेहतर सुविधाएं मिलती हैं. साथ ही, ViewPager का इस्तेमाल करने में आने वाली आम समस्याओं को हल किया जाता है. अगर आपका ऐप्लिकेशन पहले से ही ViewPager का इस्तेमाल करता है, तो ViewPager2 पर माइग्रेट करने के बारे में ज़्यादा जानने के लिए यह पेज पढ़ें.

अगर आपको अपने ऐप्लिकेशन में ViewPager2 का इस्तेमाल करना है और फ़िलहाल ViewPager का इस्तेमाल नहीं किया जा रहा है, तो ज़्यादा जानकारी के लिए ViewPager2 का इस्तेमाल करके फ़्रैगमेंट के बीच स्लाइड करना और ViewPager2 का इस्तेमाल करके टैब के साथ स्वाइप व्यू बनाना लेख पढ़ें.

ViewPager2 पर माइग्रेट करने के फ़ायदे

माइग्रेट करने की मुख्य वजह यह है कि ViewPager2 को डेवलपमेंट से जुड़ी सहायता मिल रही है, जबकि ViewPager को नहीं. हालांकि, ViewPager2 के कई अन्य फ़ायदे भी हैं.

वर्टिकल ओरिएंटेशन की सुविधा

ViewPager2 में हॉरिज़ॉन्टल पेजिंग के साथ-साथ, वर्टिकल पेजिंग की सुविधा भी मिलती है. ViewPager2 एलिमेंट के लिए वर्टिकल पेजिंग की सुविधा चालू की जा सकती है. इसके लिए, आपको उसका android:orientation एट्रिब्यूट सेट करना होगा:

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

setOrientation() तरीके का इस्तेमाल करके, इस एट्रिब्यूट को प्रोग्राम के हिसाब से भी सेट किया जा सकता है.

दाएं से बाएं लिखे जाने वाले टेक्स्ट के लिए सहायता

ViewPager2, दाईं से बाईं ओर (आरटीएल) पेजिंग की सुविधा के साथ काम करता है. जहां ज़रूरी हो वहां स्थानीय भाषा के आधार पर, आरटीएल पेजिंग अपने-आप चालू हो जाती है. हालांकि, ViewPager2 एलिमेंट के लिए आरटीएल पेजिंग को मैन्युअल तरीके से भी चालू किया जा सकता है. इसके लिए, उसका android:layoutDirection एट्रिब्यूट सेट करें:

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

setLayoutDirection() तरीके का इस्तेमाल करके, इस एट्रिब्यूट को प्रोग्राम के हिसाब से भी सेट किया जा सकता है.

बदलाव किए जा सकने वाले फ़्रैगमेंट कलेक्शन

ViewPager2, फ़्रैगमेंट के ऐसे कलेक्शन के ज़रिए पेजिंग की सुविधा देता है जिसमें बदलाव किया जा सकता है. साथ ही, कलेक्शन में बदलाव होने पर यूज़र इंटरफ़ेस (यूआई) को अपडेट करने के लिए, notifyDatasetChanged() को कॉल करता है.

इसका मतलब है कि आपका ऐप्लिकेशन, रनटाइम के दौरान फ़्रैगमेंट कलेक्शन में डाइनैमिक तौर पर बदलाव कर सकता है. साथ ही, ViewPager2, बदलाव किए गए कलेक्शन को सही तरीके से दिखाएगा.

DiffUtil

ViewPager2 को RecyclerView पर बनाया गया है. इसका मतलब है कि इसके पास DiffUtil यूटिलिटी क्लास का ऐक्सेस है. इससे कई फ़ायदे मिलते हैं. हालांकि, सबसे अहम बात यह है कि ViewPager2 ऑब्जेक्ट, RecyclerView क्लास से डेटासेट में बदलाव करने वाले ऐनिमेशन का फ़ायदा नेटिव तौर पर लेते हैं.

अपने ऐप्लिकेशन को ViewPager2 पर माइग्रेट करना

अपने ऐप्लिकेशन में ViewPager ऑब्जेक्ट को ViewPager2 में अपडेट करने के लिए, यह तरीका अपनाएं:

एक्सएमएल लेआउट फ़ाइलों को अपडेट करना

सबसे पहले, अपनी एक्सएमएल लेआउट फ़ाइलों में मौजूद ViewPager एलिमेंट को 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" />

अडैप्टर क्लास अपडेट करना

ViewPager का इस्तेमाल करते समय, आपको अडैप्टर क्लास को एक्सटेंड करना पड़ता था. इससे ऑब्जेक्ट को नए पेज मिलते थे. इस्तेमाल के उदाहरण के आधार पर, ViewPager ने तीन अलग-अलग ऐब्स्ट्रैक्ट क्लास का इस्तेमाल किया. ViewPager2 सिर्फ़ दो ऐब्सट्रैक्ट क्लास का इस्तेमाल करता है.

ViewPager2 ऑब्जेक्ट में बदले जा रहे हर ViewPager ऑब्जेक्ट के लिए, अडैप्टर क्लास को अपडेट करें, ताकि सही ऐब्स्ट्रैक्ट क्लास को इस तरह बढ़ाया जा सके:

  • जब ViewPager, व्यू के ज़रिए पेज पर जाने के लिए PagerAdapter का इस्तेमाल करे, तो ViewPager2 के साथ RecyclerView.Adapter का इस्तेमाल करें.
  • जब ViewPager का इस्तेमाल FragmentPagerAdapter के लिए किया जाता है, तो फ़्रैगमेंट की तय संख्या वाले छोटे पेज पर, FragmentStateAdapter के साथ ViewPager2 का इस्तेमाल करें.
  • जब ViewPager का इस्तेमाल FragmentStatePagerAdapter के साथ किया जाता है, तो फ़्रैगमेंट की बड़ी या अज्ञात संख्या वाले पेज पर जाने के लिए, ViewPager2 के साथ FragmentStateAdapter का इस्तेमाल करें.

कंस्ट्रक्टर पैरामीटर

FragmentPagerAdapter या FragmentStatePagerAdapter से इनहेरिट की गई फ़्रैगमेंट-आधारित अडैप्टर क्लास, कंस्ट्रक्टर पैरामीटर के तौर पर हमेशा एक FragmentManager ऑब्जेक्ट स्वीकार करती हैं. ViewPager2 अडैप्टर क्लास के लिए FragmentStateAdapter को एक्सटेंड करने पर, आपको कंस्ट्रक्टर पैरामीटर के लिए ये विकल्प मिलते हैं:

  • FragmentActivity ऑब्जेक्ट या Fragment ऑब्जेक्ट, जहां ViewPager2 ऑब्जेक्ट मौजूद है. ज़्यादातर मामलों में, यह बेहतर विकल्प होता है.
  • एक FragmentManager ऑब्जेक्ट और एक Lifecycle ऑब्जेक्ट.

RecyclerView.Adapter से सीधे तौर पर इनहेरिट होने वाली व्यू-आधारित अडैप्टर क्लास के लिए, कंस्ट्रक्टर पैरामीटर की ज़रूरत नहीं होती.

ओवरराइड करने के तरीके

आपकी अडैप्टर क्लास को ViewPager2 के लिए अलग-अलग तरीकों को भी बदलना होगा, जो उन्होंने ViewPager के लिए किया था:

  • getCount() के बजाय, getItemCount() को बदलें. नाम के अलावा, इस तरीके में कोई बदलाव नहीं हुआ है.
  • getItem() के बजाय, फ़्रैगमेंट पर आधारित अडैप्टर क्लास में createFragment() को बदलें. पक्का करें कि आपका नया createFragment() तरीका, फ़ंक्शन को कॉल किए जाने पर हर बार एक नया फ़्रैगमेंट इंस्टेंस उपलब्ध कराता हो. ऐसा करने पर, इंस्टेंस का फिर से इस्तेमाल नहीं किया जाएगा.

खास जानकारी

संक्षेप में, ViewPager2 के साथ इस्तेमाल करने के लिए, ViewPager अडैप्टर क्लास को बदलने के लिए, आपको ये बदलाव करने होंगे:

  1. व्यू के ज़रिए पेजिंग करने के लिए, सुपरक्लास को RecyclerView.Adapter में बदलें या फ़्रैगमेंट के ज़रिए पेजिंग करने के लिए, FragmentStateAdapter में बदलें.
  2. फ़्रैगमेंट पर आधारित अडैप्टर क्लास में कंस्ट्रक्टर पैरामीटर बदलें.
  3. getCount() के बजाय getItemCount() को बदलें.
  4. फ़्रैगमेंट पर आधारित अडैप्टर क्लास में, getItem() के बजाय createFragment() को बदलें.

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 इंटरफ़ेस को रीफ़ैक्टर करना

ViewPager2, TabLayout इंटिग्रेशन में बदलाव करता है. अगर फ़िलहाल, नेविगेशन के लिए हॉरिज़ॉन्टल टैब दिखाने के लिए, TabLayout ऑब्जेक्ट के साथ ViewPager का इस्तेमाल किया जा रहा है, तो आपको ViewPager2 के साथ इंटिग्रेट करने के लिए, TabLayout ऑब्जेक्ट को रीफ़ैक्टर करना होगा.

TabLayout को ViewPager2 से अलग कर दिया गया है. अब यह मटीरियल कॉम्पोनेंट के हिस्से के तौर पर उपलब्ध है. इसका मतलब है कि इसका इस्तेमाल करने के लिए, आपको अपनी build.gradle फ़ाइल में सही डिपेंडेंसी जोड़नी होगी:

Groovy

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

Kotlin

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

आपको अपनी एक्सएमएल लेआउट फ़ाइल की हैरारकी में, TabLayout एलिमेंट की जगह भी बदलनी होगी. ViewPager के साथ, TabLayout एलिमेंट को ViewPager एलिमेंट के चाइल्ड के तौर पर एलान किया जाता है. हालांकि, ViewPager2 के साथ, TabLayout एलिमेंट को सीधे ViewPager2 एलिमेंट के ऊपर, उसी लेवल पर एलान किया जाता है:

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

आखिर में, आपको उस कोड को अपडेट करना होगा जो TabLayout ऑब्जेक्ट को ViewPager ऑब्जेक्ट से अटैच करता है. TabLayout, ViewPager के साथ इंटिग्रेट करने के लिए, अपने setupWithViewPager() तरीके का इस्तेमाल करता है. हालांकि, ViewPager2 के साथ इंटिग्रेट करने के लिए, इसे TabLayoutMediator इंस्टेंस की ज़रूरत होती है.

TabLayoutMediator ऑब्जेक्ट, TabLayout ऑब्जेक्ट के लिए पेज के टाइटल जनरेट करने का काम भी करता है. इसका मतलब है कि अडैप्टर क्लास को 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();
    }
    ...
}

नेस्ट किए गए स्क्रोल किए जा सकने वाले एलिमेंट के साथ काम करना

ViewPager2 में, नेस्ट किए गए स्क्रोल व्यू के लिए नेटिव तौर पर सहायता उपलब्ध नहीं है. ऐसा उन मामलों में होता है जहां स्क्रोल व्यू का ओरिएंटेशन, उसे शामिल करने वाले ViewPager2 ऑब्जेक्ट के ओरिएंटेशन जैसा ही होता है. उदाहरण के लिए, वर्टिकल ओरिएंटेशन वाले ViewPager2 ऑब्जेक्ट में, वर्टिकल स्क्रोल व्यू के लिए स्क्रोल करने की सुविधा काम नहीं करेगी.

एक ही ओरिएंटेशन वाले ViewPager2 ऑब्जेक्ट के अंदर स्क्रोल व्यू को सपोर्ट करने के लिए, आपको ViewPager2 ऑब्जेक्ट पर requestDisallowInterceptTouchEvent() को कॉल करना होगा. ऐसा तब करना होगा, जब आपको नेस्ट किए गए एलिमेंट को स्क्रोल करना हो. ViewPager2 नेस्टेड स्क्रोलिंग सैंपल, इस समस्या को हल करने का एक तरीका दिखाता है. इसके लिए, कई तरह के काम करने वाले कस्टम रैपर लेआउट का इस्तेमाल किया जाता है.

अन्य संसाधन

ViewPager2 के बारे में ज़्यादा जानने के लिए, यहां दिए गए अन्य संसाधन देखें.

वीडियो