از ViewPager به ViewPager2 مهاجرت کنید

ViewPager2 یک نسخه بهبود یافته از کتابخانه ViewPager است که عملکردهای پیشرفته‌تری را ارائه می‌دهد و مشکلات رایج در استفاده ViewPager را برطرف می‌کند. اگر برنامه شما قبلاً از ViewPager استفاده می‌کند، این صفحه را بخوانید تا درباره مهاجرت به ViewPager2 اطلاعات بیشتری کسب کنید.

اگر می‌خواهید از ViewPager2 در برنامه خود استفاده کنید و در حال حاضر از ViewPager استفاده نمی‌کنید، برای اطلاعات بیشتر ، Slide بین قطعات با استفاده از ViewPager2 و Create views Swipe with Tabs با استفاده از 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 از صفحه‌بندی راست به چپ (RTL) پشتیبانی می‌کند. صفحه‌بندی RTL به‌طور خودکار در صورت لزوم بر اساس محلی فعال می‌شود، اما می‌توانید با تنظیم ویژگی android:layoutDirection صفحه‌بندی RTL را برای عنصر ViewPager2 به صورت دستی فعال کنید:

<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 دنبال کنید:

فایل های طرح بندی XML را به روز کنید

ابتدا عناصر ViewPager را در فایل های طرح بندی XML خود با عناصر 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 فقط از دو کلاس انتزاعی استفاده می کند.

برای هر شی ViewPager که به یک شی ViewPager2 تبدیل می کنید، کلاس آداپتور را به روز کنید تا کلاس انتزاعی مناسب را به صورت زیر گسترش دهید:

  • وقتی ViewPager از PagerAdapter برای صفحه از طریق نماها استفاده کرد، از RecyclerView.Adapter با ViewPager2 استفاده کنید.
  • وقتی ViewPager از FragmentPagerAdapter برای صفحه‌بندی تعداد کمی از قطعات ثابت استفاده می‌کرد، از FragmentStateAdapter با ViewPager2 استفاده کنید.
  • هنگامی که ViewPager از FragmentStatePagerAdapter برای صفحه در تعداد زیادی یا ناشناخته قطعه استفاده کرد، از FragmentStateAdapter با ViewPager2 استفاده کنید.

پارامترهای سازنده

کلاس‌های آداپتور مبتنی بر Fragment که از FragmentPagerAdapter یا FragmentStatePagerAdapter به ارث می‌برند، همیشه یک شی FragmentManager را به عنوان پارامتر سازنده می‌پذیرند. وقتی FragmentStateAdapter برای یک کلاس آداپتور ViewPager2 گسترش می دهید، به جای آن گزینه های زیر را برای پارامترهای سازنده دارید:

  • شیء FragmentActivity یا شیء Fragment که شی ViewPager2 در آن قرار دارد. در بیشتر موارد، این گزینه بهتر است.
  • یک شیء FragmentManager و یک شیء Lifecycle .

کلاس‌های آداپتور مبتنی بر View که مستقیماً از RecyclerView.Adapter به ارث می‌برند، به پارامتر سازنده نیاز ندارند.

نادیده گرفتن روش ها

کلاس‌های آداپتور شما همچنین باید روش‌های مختلفی را برای ViewPager2 نسبت به ViewPager نادیده بگیرند:

  • به جای getCount() ، getItemCount() را لغو کنید. به غیر از نام، این روش بدون تغییر است.
  • به‌جای getItem() ، در کلاس‌های آداپتور مبتنی بر قطعه، createFragment() را لغو کنید. مطمئن شوید که متد createFragment() جدید شما همیشه هر بار که تابع فراخوانی می شود به جای استفاده مجدد از نمونه ها، یک نمونه قطعه جدید ارائه می کند.

خلاصه

به طور خلاصه، برای تبدیل یک کلاس آداپتور ViewPager برای استفاده با ViewPager2 ، باید تغییرات زیر را اعمال کنید:

  1. سوپرکلاس را به RecyclerView.Adapter برای صفحه‌بندی از طریق نماها یا FragmentStateAdapter برای صفحه‌بندی از طریق قطعات تغییر دهید.
  2. پارامترهای سازنده را در کلاس های آداپتور مبتنی بر قطعه تغییر دهید.
  3. به جای getCount() getItemCount() را لغو کنید.
  4. در کلاس‌های آداپتور مبتنی بر فرگمنت، به جای getItem() createFragment() لغو کنید.

کاتلین

// 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()
}

جاوا

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

رابط های Refactor TabLayout

ViewPager2 تغییراتی را در ادغام TabLayout معرفی می کند. اگر در حال حاضر از یک ViewPager با یک شی TabLayout برای نمایش برگه های افقی برای پیمایش استفاده می کنید، باید شی TabLayout را برای ادغام با ViewPager2 تغییر دهید.

TabLayout از ViewPager2 جدا شده است و اکنون به عنوان بخشی از اجزای Material در دسترس است. این بدان معناست که برای استفاده از آن، باید وابستگی مناسب را به فایل build.gradle خود اضافه کنید:

شیار

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

کاتلین

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

همچنین باید مکان عنصر TabLayout را در سلسله مراتب فایل طرح بندی XML خود تغییر دهید. با 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 از متد setupWithViewPager() خود برای ادغام با ViewPager استفاده می کند، برای ادغام با ViewPager2 به یک نمونه TabLayoutMediator نیاز دارد.

شی TabLayoutMediator همچنین وظیفه تولید عناوین صفحه برای شی TabLayout را بر عهده دارد، به این معنی که کلاس آداپتور نیازی به لغو getPageTitle() ندارد:

کاتلین

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

جاوا

// 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 با جهت‌گیری یکسان، باید requestDisallowInterceptTouchEvent() را در شی ViewPager2 فراخوانی کنید، زمانی که انتظار دارید به جای آن عنصر تودرتو را اسکرول کنید. نمونه پیمایش تودرتو ViewPager2 یکی از راه‌های حل این مشکل را با طرح‌بندی بسته‌بندی سفارشی همه کاره نشان می‌دهد.

منابع اضافی

برای کسب اطلاعات بیشتر در مورد ViewPager2 ، به منابع اضافی زیر مراجعه کنید.

نمونه ها

ویدیوها