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 ، باید تغییرات زیر را اعمال کنید:
- سوپرکلاس را به
RecyclerView.Adapterبرای صفحهبندی از طریق نماها یاFragmentStateAdapterبرای صفحهبندی از طریق قطعات تغییر دهید. - پارامترهای سازنده را در کلاس های آداپتور مبتنی بر قطعه تغییر دهید.
- به جای
getCount()getItemCount()را لغو کنید. - در کلاسهای آداپتور مبتنی بر فرگمنت، به جای
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 ، به منابع اضافی زیر مراجعه کنید.
نمونه ها
- نمونه های ViewPager2 در GitHub
ویدیوها
- چرخاندن صفحه: مهاجرت به ViewPager2 (Android Dev Summit '19)